ensure_capabilities(); } /** * Ensure required capabilities exist */ private function ensure_capabilities() { $master_role = get_role('hvac_master_trainer'); if ($master_role && !$master_role->has_cap('hvac_master_manage_approvals')) { $master_role->add_cap('hvac_master_manage_approvals'); } // Also add to admin role $admin_role = get_role('administrator'); if ($admin_role && !$admin_role->has_cap('hvac_master_manage_approvals')) { $admin_role->add_cap('hvac_master_manage_approvals'); } } /** * Check if current user can manage approvals * * @return bool */ public function can_manage_approvals() { $user = wp_get_current_user(); return in_array('hvac_master_trainer', $user->roles) || current_user_can('hvac_master_manage_approvals') || current_user_can('manage_options'); } /** * Render pending approvals interface */ public function render_pending_approvals($atts = array()) { // Check permissions if (!$this->can_manage_approvals()) { return '
You do not have permission to access this page.
'; } // Get filters from request $status_filter = sanitize_text_field($_GET['status_filter'] ?? 'pending'); $region_filter = sanitize_text_field($_GET['region_filter'] ?? ''); $date_from = sanitize_text_field($_GET['date_from'] ?? ''); $date_to = sanitize_text_field($_GET['date_to'] ?? ''); $search_term = sanitize_text_field($_GET['search'] ?? ''); $page = max(1, intval($_GET['paged'] ?? 1)); $per_page = 20; // Get trainers data $trainers_data = $this->get_trainers_data(array( 'status' => $status_filter, 'region' => $region_filter, 'date_from' => $date_from, 'date_to' => $date_to, 'search' => $search_term, 'page' => $page, 'per_page' => $per_page )); ob_start(); ?>

Trainer Approvals

Review and manage trainer registration approvals

Reset

No trainers found matching your criteria.

Date Name Location Status Actions
user_registered))); ?> get_trainer_location($trainer->ID)); ?> get_status_badge(HVAC_Trainer_Status::get_trainer_status($trainer->ID)); ?> ID); ?>
$per_page): ?>
$status_filter, 'region_filter' => $region_filter, 'date_from' => $date_from, 'date_to' => $date_to, 'search' => $search_term ), $base_url); for ($i = 1; $i <= $total_pages; $i++): $url = add_query_arg('paged', $i, $base_url); $active_class = ($i === $page) ? 'active' : ''; ?>
render_modals(); ?> 'pending', 'region' => '', 'date_from' => '', 'date_to' => '', 'search' => '', 'page' => 1, 'per_page' => 20 ); $args = wp_parse_args($args, $defaults); // Base query args $query_args = array( 'role__in' => array('hvac_trainer', 'hvac_master_trainer'), 'number' => $args['per_page'], 'offset' => ($args['page'] - 1) * $args['per_page'], 'meta_query' => array(), 'date_query' => array() ); // Status filter if ($args['status'] !== 'all') { if ($args['status'] === 'rejected') { // Handle rejected status - stored as disabled $query_args['meta_query'][] = array( 'key' => 'account_status', 'value' => 'disabled', 'compare' => '=' ); } else { $query_args['meta_query'][] = array( 'key' => 'account_status', 'value' => $args['status'], 'compare' => '=' ); } } // Date filters if (!empty($args['date_from']) || !empty($args['date_to'])) { $date_query = array(); if (!empty($args['date_from'])) { $date_query['after'] = $args['date_from']; } if (!empty($args['date_to'])) { $date_query['before'] = $args['date_to'] . ' 23:59:59'; } if (!empty($date_query)) { $query_args['date_query'] = array($date_query); } } // Search filter if (!empty($args['search'])) { $query_args['search'] = '*' . $args['search'] . '*'; $query_args['search_columns'] = array('display_name', 'user_login', 'user_email'); } // Region filter if (!empty($args['region'])) { $query_args['meta_query'][] = array( 'relation' => 'OR', array( 'key' => 'state', 'value' => $args['region'], 'compare' => '=' ), array( 'key' => 'country', 'value' => $args['region'], 'compare' => '=' ) ); } // Get total count for pagination $count_args = $query_args; unset($count_args['number'], $count_args['offset']); $total_query = new WP_User_Query($count_args); $total = $total_query->get_total(); // Get trainers $user_query = new WP_User_Query($query_args); $trainers = $user_query->get_results(); return array( 'trainers' => $trainers, 'total' => $total, 'query_args' => $query_args ); } /** * Get available regions from trainer data */ private function get_regions() { global $wpdb; // Get unique states and countries from trainer meta $regions = $wpdb->get_col( "SELECT DISTINCT meta_value FROM {$wpdb->usermeta} um INNER JOIN {$wpdb->users} u ON um.user_id = u.ID INNER JOIN {$wpdb->usermeta} um_role ON u.ID = um_role.user_id WHERE um.meta_key IN ('state', 'country') AND um.meta_value != '' AND um_role.meta_key = 'wp_capabilities' AND (um_role.meta_value LIKE '%hvac_trainer%' OR um_role.meta_value LIKE '%hvac_master_trainer%') ORDER BY meta_value" ); return array_filter($regions); } /** * Get trainer location string */ private function get_trainer_location($user_id) { $city = get_user_meta($user_id, 'city', true); $state = get_user_meta($user_id, 'state', true); $country = get_user_meta($user_id, 'country', true); $location_parts = array_filter(array($city, $state, $country)); return !empty($location_parts) ? implode(', ', $location_parts) : 'Not specified'; } /** * Get status badge HTML */ private function get_status_badge($status) { $badges = array( 'pending' => 'Pending', 'approved' => 'Approved', 'active' => 'Active', 'inactive' => 'Inactive', 'disabled' => 'Rejected' ); return isset($badges[$status]) ? $badges[$status] : '' . esc_html(ucfirst($status)) . ''; } /** * Render modal dialogs */ private function render_modals() { ?> $security_check->get_error_message(), 'code' => $security_check->get_error_code() ), $security_check->get_error_data() ? $security_check->get_error_data()['status'] : 403 ); return; } } else { // Fallback to original security check check_ajax_referer('hvac_master_approvals', 'nonce'); // Check permissions if (!$this->can_manage_approvals()) { wp_send_json_error(array('message' => 'Insufficient permissions.'), 403); return; } } // Enhanced input validation $validation_rules = array( 'user_id' => array( 'type' => 'int', 'required' => true, 'min' => 1 ), 'reason' => array( 'type' => 'textarea', 'required' => false, 'max_length' => 1000 ) ); // Use centralized sanitization if available if (class_exists('HVAC_Ajax_Security')) { $data = HVAC_Ajax_Security::sanitize_input($_POST, $validation_rules); if (is_wp_error($data)) { wp_send_json_error( array( 'message' => $data->get_error_message(), 'errors' => $data->get_error_data() ), 400 ); return; } $user_id = $data['user_id']; $reason = isset($data['reason']) ? $data['reason'] : ''; } else { // Fallback to basic sanitization $user_id = intval($_POST['user_id'] ?? 0); $reason = sanitize_textarea_field($_POST['reason'] ?? ''); // Validate length if (strlen($reason) > 1000) { wp_send_json_error(array('message' => 'Reason text too long (max 1000 characters).'), 400); return; } if (!$user_id || $user_id < 1) { wp_send_json_error(array('message' => 'Invalid user ID.'), 400); return; } } // Get trainer info with additional validation $trainer = get_userdata($user_id); if (!$trainer) { wp_send_json_error(array('message' => 'Trainer not found.'), 404); return; } // Verify this is actually a trainer $is_trainer = in_array('hvac_trainer', $trainer->roles) || get_user_meta($user_id, 'hvac_trainer_status', true); if (!$is_trainer) { wp_send_json_error(array('message' => 'User is not a trainer.'), 400); return; } // Check if already approved to prevent duplicate processing $current_status = get_user_meta($user_id, 'hvac_trainer_status', true); if ($current_status === 'approved') { wp_send_json_error(array('message' => 'Trainer is already approved.'), 400); return; } // Begin transaction-like operation $approval_data = array( 'user_id' => $user_id, 'previous_status' => $current_status, 'new_status' => 'approved', 'approved_by' => get_current_user_id(), 'approved_date' => current_time('mysql'), 'reason' => $reason ); // Update status using existing system with error handling try { $result = false; if (class_exists('HVAC_Trainer_Status')) { $result = HVAC_Trainer_Status::set_trainer_status($user_id, HVAC_Trainer_Status::STATUS_APPROVED); } else { // Fallback implementation update_user_meta($user_id, 'hvac_trainer_status', 'approved'); update_user_meta($user_id, 'hvac_trainer_approved_date', $approval_data['approved_date']); update_user_meta($user_id, 'hvac_trainer_approved_by', $approval_data['approved_by']); // Ensure trainer role is assigned $trainer->add_role('hvac_trainer'); $result = true; } if ($result) { // Store approval reason if provided if (!empty($reason)) { update_user_meta($user_id, 'hvac_trainer_approval_reason', $reason); } // Log the approval action with enhanced audit trail $this->log_approval_action($user_id, 'approved', $reason); // Additional security logging if (class_exists('HVAC_Logger')) { HVAC_Logger::info('Trainer approval successful', 'Security', $approval_data); } // Clear any related caches delete_transient('hvac_pending_trainers_count'); delete_transient('hvac_trainers_list_' . $current_status); wp_send_json_success(array( 'message' => sprintf('Trainer %s has been approved successfully.', esc_html($trainer->display_name)), 'user_id' => $user_id, 'new_status' => 'approved', 'timestamp' => $approval_data['approved_date'] )); } else { throw new Exception('Failed to update trainer status'); } } catch (Exception $e) { // Log the failure if (class_exists('HVAC_Logger')) { HVAC_Logger::error('Trainer approval failed', 'Security', array( 'user_id' => $user_id, 'error' => $e->getMessage(), 'approval_data' => $approval_data )); } wp_send_json_error(array('message' => 'Failed to approve trainer: ' . $e->getMessage()), 500); } } /** * AJAX: Reject trainer */ public function ajax_reject_trainer() { // Check nonce check_ajax_referer('hvac_master_approvals', 'nonce'); // Check permissions if (!$this->can_manage_approvals()) { wp_send_json_error(array('message' => 'Insufficient permissions.')); } $user_id = intval($_POST['user_id'] ?? 0); $reason = sanitize_textarea_field($_POST['reason'] ?? ''); if (!$user_id) { wp_send_json_error(array('message' => 'Invalid user ID.')); } // Get trainer info $trainer = get_userdata($user_id); if (!$trainer) { wp_send_json_error(array('message' => 'Trainer not found.')); } // Update status - use disabled for rejected $result = HVAC_Trainer_Status::set_trainer_status($user_id, HVAC_Trainer_Status::STATUS_DISABLED); if ($result) { // Log the rejection action $this->log_approval_action($user_id, 'rejected', $reason); wp_send_json_success(array( 'message' => sprintf('Trainer %s has been rejected.', $trainer->display_name), 'user_id' => $user_id, 'new_status' => 'rejected' )); } else { wp_send_json_error(array('message' => 'Failed to reject trainer.')); } } /** * AJAX: Bulk trainer actions */ public function ajax_bulk_trainer_action() { // Check nonce check_ajax_referer('hvac_master_approvals', 'nonce'); // Check permissions if (!$this->can_manage_approvals()) { wp_send_json_error(array('message' => 'Insufficient permissions.')); } $user_ids = array_map('intval', $_POST['user_ids'] ?? array()); $action = sanitize_text_field($_POST['action'] ?? ''); $reason = sanitize_textarea_field($_POST['reason'] ?? ''); if (empty($user_ids) || !in_array($action, array('approve', 'reject'))) { wp_send_json_error(array('message' => 'Invalid parameters.')); } $success_count = 0; $failed_count = 0; $results = array(); foreach ($user_ids as $user_id) { $trainer = get_userdata($user_id); if (!$trainer) { $failed_count++; continue; } $new_status = ($action === 'approve') ? HVAC_Trainer_Status::STATUS_APPROVED : HVAC_Trainer_Status::STATUS_DISABLED; if (HVAC_Trainer_Status::set_trainer_status($user_id, $new_status)) { $this->log_approval_action($user_id, $action === 'approve' ? 'approved' : 'rejected', $reason); $success_count++; $results[$user_id] = 'success'; } else { $failed_count++; $results[$user_id] = 'failed'; } } $message = sprintf( 'Bulk %s completed: %d successful, %d failed', $action === 'approve' ? 'approval' : 'rejection', $success_count, $failed_count ); wp_send_json_success(array( 'message' => $message, 'success_count' => $success_count, 'failed_count' => $failed_count, 'results' => $results )); } /** * AJAX: Get trainer details */ public function ajax_get_trainer_details() { // Check nonce check_ajax_referer('hvac_master_approvals', 'nonce'); // Check permissions if (!$this->can_manage_approvals()) { wp_send_json_error(array('message' => 'Insufficient permissions.')); } $user_id = intval($_POST['user_id'] ?? 0); if (!$user_id) { wp_send_json_error(array('message' => 'Invalid user ID.')); } $trainer = get_userdata($user_id); if (!$trainer) { wp_send_json_error(array('message' => 'Trainer not found.')); } // Get trainer meta data $trainer_data = array( 'display_name' => $trainer->display_name, 'user_email' => $trainer->user_email, 'user_registered' => date('F j, Y', strtotime($trainer->user_registered)), 'first_name' => get_user_meta($user_id, 'first_name', true), 'last_name' => get_user_meta($user_id, 'last_name', true), 'phone' => get_user_meta($user_id, 'phone', true), 'business_name' => get_user_meta($user_id, 'business_name', true), 'business_email' => get_user_meta($user_id, 'business_email', true), 'business_phone' => get_user_meta($user_id, 'business_phone', true), 'business_website' => get_user_meta($user_id, 'business_website', true), 'city' => get_user_meta($user_id, 'city', true), 'state' => get_user_meta($user_id, 'state', true), 'country' => get_user_meta($user_id, 'country', true), 'application_details' => get_user_meta($user_id, 'application_details', true), 'business_type' => get_user_meta($user_id, 'business_type', true), 'training_audience' => get_user_meta($user_id, 'training_audience', true), 'status' => HVAC_Trainer_Status::get_trainer_status($user_id), 'approval_log' => get_user_meta($user_id, 'hvac_approval_log', true) ); // Build HTML content ob_start(); ?>

Personal Information

Name:
Email:
Phone:
Registration Date:

Business Information

Business Name:
Business Email:
Business Phone:
Website:
Business Type:

Location

City:
State/Province:
Country:

Application Details

Approval History

by on
Reason:

Current Status

get_status_badge($trainer_data['status']); ?>

ob_get_clean(), 'data' => $trainer_data )); } /** * Log approval action to user meta */ private function log_approval_action($user_id, $action, $reason = '') { $current_user = wp_get_current_user(); $log_entry = array( 'action' => ucfirst($action), 'user' => $current_user->display_name, 'user_id' => $current_user->ID, 'date' => current_time('mysql'), 'reason' => $reason ); // Get existing log $approval_log = get_user_meta($user_id, 'hvac_approval_log', true); if (!is_array($approval_log)) { $approval_log = array(); } // Add new entry $approval_log[] = $log_entry; // Store updated log update_user_meta($user_id, 'hvac_approval_log', $approval_log); } } // Initialize the class HVAC_Master_Pending_Approvals::instance();