upskill-event-manager/includes/class-hvac-master-trainers-overview.php
Ben c3e7fe9140 feat: comprehensive HVAC plugin development framework and modernization
## Major Enhancements

### 🏗️ Architecture & Infrastructure
- Implement comprehensive Docker testing infrastructure with hermetic environment
- Add Forgejo Actions CI/CD pipeline for automated deployments
- Create Page Object Model (POM) testing architecture reducing test duplication by 90%
- Establish security-first development patterns with input validation and output escaping

### 🧪 Testing Framework Modernization
- Migrate 146+ tests from 80 duplicate files to centralized architecture
- Add comprehensive E2E test suites for all user roles and workflows
- Implement WordPress error detection with automatic site health monitoring
- Create robust browser lifecycle management with proper cleanup

### 📚 Documentation & Guides
- Add comprehensive development best practices guide
- Create detailed administrator setup documentation
- Establish user guides for trainers and master trainers
- Document security incident reports and migration guides

### 🔧 Core Plugin Features
- Enhance trainer profile management with certification system
- Improve find trainer functionality with advanced filtering
- Strengthen master trainer area with content management
- Add comprehensive venue and organizer management

### 🛡️ Security & Reliability
- Implement security-first patterns throughout codebase
- Add comprehensive input validation and output escaping
- Create secure credential management system
- Establish proper WordPress role-based access control

### 🎯 WordPress Integration
- Strengthen singleton pattern implementation across all classes
- Enhance template hierarchy with proper WordPress integration
- Improve page manager with hierarchical URL structure
- Add comprehensive shortcode and menu system

### 🔍 Developer Experience
- Add extensive debugging and troubleshooting tools
- Create comprehensive test data seeding scripts
- Implement proper error handling and logging
- Establish consistent code patterns and standards

### 📊 Performance & Optimization
- Optimize database queries and caching strategies
- Improve asset loading and script management
- Enhance template rendering performance
- Streamline user experience across all interfaces

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-29 11:26:10 -03:00

391 lines
No EOL
12 KiB
PHP

<?php
/**
* HVAC Master Trainers Overview
*
* Provides comprehensive trainers overview for master trainers with read-only access
* to all trainer profiles with filtering and statistics.
*
* @package HVAC Community Events
* @subpackage Includes
* @author Ben Reed
* @version 1.0.0
*/
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/**
* Class HVAC_Master_Trainers_Overview
*
* Handles comprehensive read-only trainers overview for master trainers
*/
class HVAC_Master_Trainers_Overview {
/**
* Instance
*/
private static $instance = null;
/**
* Master dashboard data instance
*/
private $dashboard_data = null;
/**
* Get instance (singleton pattern)
*/
public static function instance() {
if ( is_null( self::$instance ) ) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor
*/
private function __construct() {
// Load dependencies
$this->load_dependencies();
// Initialize hooks
$this->init_hooks();
// Initialize dashboard data
if ( class_exists( 'HVAC_Master_Dashboard_Data' ) ) {
$this->dashboard_data = new HVAC_Master_Dashboard_Data();
}
}
/**
* Load required dependencies
*/
private function load_dependencies() {
// Ensure master dashboard data is available
if ( ! class_exists( 'HVAC_Master_Dashboard_Data' ) ) {
require_once HVAC_PLUGIN_DIR . 'includes/class-hvac-master-dashboard-data.php';
}
}
/**
* Initialize hooks
*/
private function init_hooks() {
// AJAX handlers for trainers overview
add_action( 'wp_ajax_hvac_master_trainers_filter', array( $this, 'ajax_filter_trainers' ) );
add_action( 'wp_ajax_hvac_master_trainers_stats', array( $this, 'ajax_get_stats' ) );
// Shortcode for embedding trainers overview
add_shortcode( 'hvac_master_trainers', array( $this, 'render_trainers_overview' ) );
// Add function for template integration
add_action( 'init', array( $this, 'register_template_functions' ) );
}
/**
* Register template functions
*/
public function register_template_functions() {
if ( ! function_exists( 'hvac_render_master_trainers' ) ) {
function hvac_render_master_trainers() {
$overview = HVAC_Master_Trainers_Overview::instance();
return $overview->render_trainers_overview();
}
}
}
/**
* Render the complete trainers overview
*/
public function render_trainers_overview( $atts = array() ) {
// Security check
if ( ! $this->can_view_trainers() ) {
return '<div class="hvac-notice hvac-notice-error">You do not have permission to view trainers overview.</div>';
}
ob_start();
?>
<div class="hvac-master-trainers-overview" id="hvac-master-trainers-overview">
<!-- Stats Section -->
<div class="hvac-trainers-stats-section">
<div class="hvac-stats-loading" id="hvac-stats-loading">
<div class="hvac-spinner"></div>
<p>Loading trainer statistics...</p>
</div>
<div class="hvac-stats-tiles" id="hvac-stats-tiles" style="display: none;">
<!-- Stats tiles will be loaded via AJAX -->
</div>
</div>
<!-- Filters Section -->
<div class="hvac-trainers-filters-section">
<form class="hvac-trainers-filters" id="hvac-trainers-filters">
<div class="hvac-filters-row">
<!-- Status Filter -->
<div class="hvac-filter-group">
<label for="filter-status">Status:</label>
<select id="filter-status" name="status">
<option value="all">All Trainers</option>
<option value="active">Active</option>
<option value="inactive">Inactive</option>
<option value="pending">Pending</option>
<option value="disabled">Disabled</option>
</select>
</div>
<!-- Region Filter -->
<div class="hvac-filter-group">
<label for="filter-region">Region:</label>
<select id="filter-region" name="region">
<option value="">All Regions</option>
<?php echo $this->get_regions_options(); ?>
</select>
</div>
<!-- Search Filter -->
<div class="hvac-filter-group hvac-filter-search">
<label for="filter-search">Search:</label>
<input type="text" id="filter-search" name="search" placeholder="Trainer name or email..." />
</div>
<!-- Filter Actions -->
<div class="hvac-filter-actions">
<button type="submit" class="hvac-btn hvac-btn-primary">Filter Trainers</button>
<button type="button" class="hvac-btn hvac-btn-secondary" id="clear-filters">Clear All</button>
</div>
</div>
</form>
</div>
<!-- Trainers Content Section -->
<div class="hvac-trainers-content">
<div class="hvac-trainers-table-view" id="hvac-trainers-table-view">
<div class="hvac-trainers-loading" id="hvac-trainers-loading">
<div class="hvac-spinner"></div>
<p>Loading trainers...</p>
</div>
<div class="hvac-trainers-table-container" id="hvac-trainers-table-container" style="display: none;">
<!-- Trainers table will be loaded via AJAX -->
</div>
</div>
</div>
</div>
<!-- Hidden nonce for AJAX -->
<?php wp_nonce_field( 'hvac_master_trainers_nonce', 'hvac_master_trainers_nonce', false ); ?>
<script type="text/javascript">
// Pass AJAX URL and nonce to JavaScript
var hvac_master_trainers_ajax = {
ajax_url: '<?php echo esc_js( admin_url( 'admin-ajax.php' ) ); ?>',
nonce: '<?php echo esc_js( wp_create_nonce( 'hvac_master_trainers_nonce' ) ); ?>'
};
</script>
<?php
return ob_get_clean();
}
/**
* Get regions options for filter dropdown
*/
private function get_regions_options() {
if ( ! $this->dashboard_data ) {
return '';
}
$trainer_stats = $this->dashboard_data->get_trainer_statistics();
$regions = array();
$options = '';
if ( ! empty( $trainer_stats['trainer_data'] ) ) {
foreach ( $trainer_stats['trainer_data'] as $trainer ) {
$user_meta = get_user_meta( $trainer->trainer_id );
$state = isset( $user_meta['billing_state'] ) ? $user_meta['billing_state'][0] : '';
$country = isset( $user_meta['billing_country'] ) ? $user_meta['billing_country'][0] : '';
if ( ! empty( $state ) && ! in_array( $state, $regions ) ) {
$regions[] = $state;
}
}
}
sort( $regions );
foreach ( $regions as $region ) {
$options .= sprintf(
'<option value="%s">%s</option>',
esc_attr( $region ),
esc_html( $region )
);
}
return $options;
}
/**
* AJAX handler for filtering trainers
*/
public function ajax_filter_trainers() {
// Verify nonce
if ( ! wp_verify_nonce( $_POST['nonce'], 'hvac_master_trainers_nonce' ) ) {
wp_send_json_error( array( 'message' => 'Security check failed' ) );
}
// Check permissions
if ( ! $this->can_view_trainers() ) {
wp_send_json_error( array( 'message' => 'Insufficient permissions' ) );
}
// Get filter parameters
$args = array(
'status' => isset( $_POST['status'] ) ? sanitize_text_field( $_POST['status'] ) : 'all',
'region' => isset( $_POST['region'] ) ? sanitize_text_field( $_POST['region'] ) : '',
'search' => isset( $_POST['search'] ) ? sanitize_text_field( $_POST['search'] ) : '',
'page' => isset( $_POST['page'] ) ? absint( $_POST['page'] ) : 1,
'per_page' => isset( $_POST['per_page'] ) ? absint( $_POST['per_page'] ) : 20,
'orderby' => isset( $_POST['orderby'] ) ? sanitize_text_field( $_POST['orderby'] ) : 'display_name',
'order' => isset( $_POST['order'] ) ? sanitize_text_field( $_POST['order'] ) : 'ASC',
);
// Get trainers data
if ( $this->dashboard_data ) {
$trainer_stats = $this->dashboard_data->get_trainer_statistics();
// Format trainers for display
$formatted_trainers = $this->format_trainers_for_display( $trainer_stats['trainer_data'], $args );
wp_send_json_success( array(
'trainers' => $formatted_trainers,
'total_found' => count( $formatted_trainers )
) );
}
wp_send_json_error( array( 'message' => 'Unable to load trainers data' ) );
}
/**
* AJAX handler for getting trainer stats
*/
public function ajax_get_stats() {
// Verify nonce
if ( ! wp_verify_nonce( $_POST['nonce'], 'hvac_master_trainers_nonce' ) ) {
wp_send_json_error( array( 'message' => 'Security check failed' ) );
}
// Check permissions
if ( ! $this->can_view_trainers() ) {
wp_send_json_error( array( 'message' => 'Insufficient permissions' ) );
}
if ( $this->dashboard_data ) {
$trainer_stats = $this->dashboard_data->get_trainer_statistics();
$stats = array(
'total_trainers' => $trainer_stats['total_trainers'],
'active_trainers' => $this->count_trainers_by_status( 'active' ),
'pending_trainers' => $this->count_trainers_by_status( 'pending' ),
'total_events' => $trainer_stats['total_events'],
'total_revenue' => $trainer_stats['total_revenue']
);
wp_send_json_success( $stats );
}
wp_send_json_error( array( 'message' => 'Unable to load trainer stats' ) );
}
/**
* Format trainers for table display
*/
private function format_trainers_for_display( $trainers, $filters = array() ) {
$formatted = array();
foreach ( $trainers as $trainer ) {
$user_meta = get_user_meta( $trainer->trainer_id );
$user_data = get_userdata( $trainer->trainer_id );
if ( ! $user_data ) continue;
// Apply filters
if ( ! empty( $filters['search'] ) ) {
$search_term = strtolower( $filters['search'] );
$search_fields = strtolower( $trainer->display_name . ' ' . $user_data->user_email );
if ( strpos( $search_fields, $search_term ) === false ) {
continue;
}
}
if ( ! empty( $filters['region'] ) ) {
$user_state = isset( $user_meta['billing_state'] ) ? $user_meta['billing_state'][0] : '';
if ( $user_state !== $filters['region'] ) {
continue;
}
}
$status = isset( $user_meta['hvac_trainer_status'] ) ? $user_meta['hvac_trainer_status'][0] : 'active';
if ( $filters['status'] !== 'all' && $status !== $filters['status'] ) {
continue;
}
$formatted[] = array(
'id' => $trainer->trainer_id,
'name' => $trainer->display_name,
'email' => $user_data->user_email,
'status' => ucfirst( $status ),
'status_class' => 'hvac-status-' . esc_attr( $status ),
'total_events' => $trainer->total_events,
'location' => $this->get_trainer_location( $user_meta ),
'registered' => date( 'M j, Y', strtotime( $user_data->user_registered ) ),
'profile_link' => home_url( '/master-trainer/trainer-profile/' . $trainer->trainer_id . '/' ),
'edit_link' => home_url( '/master-trainer/edit-trainer/' . $trainer->trainer_id . '/' )
);
}
return $formatted;
}
/**
* Get trainer location from user meta
*/
private function get_trainer_location( $user_meta ) {
$city = isset( $user_meta['billing_city'] ) ? $user_meta['billing_city'][0] : '';
$state = isset( $user_meta['billing_state'] ) ? $user_meta['billing_state'][0] : '';
$country = isset( $user_meta['billing_country'] ) ? $user_meta['billing_country'][0] : '';
$location_parts = array_filter( array( $city, $state, $country ) );
return implode( ', ', $location_parts );
}
/**
* Count trainers by status
*/
private function count_trainers_by_status( $status ) {
$users = get_users( array(
'role' => 'hvac_trainer',
'meta_key' => 'hvac_trainer_status',
'meta_value' => $status,
'count_total' => true
) );
return is_array( $users ) ? count( $users ) : 0;
}
/**
* Check if current user can view trainers
*/
private function can_view_trainers() {
$user = wp_get_current_user();
return in_array( 'hvac_master_trainer', $user->roles ) || current_user_can( 'manage_options' );
}
}
// Initialize the class
HVAC_Master_Trainers_Overview::instance();