upskill-event-manager/templates/page-trainer-dashboard.php
Ben 8be49ad5a9 fix: comprehensive dashboard fixes and improvements
- Fixed critical security vulnerability with incorrect capability checks
- Fixed hardcoded redirect path from /community-login/ to /training-login/
- Moved dashboard shortcode registration to centralized location
- Fixed duplicate class loading with proper singleton checks
- Fixed incorrect edit URLs in dashboard
- Removed debug HTML comments from production templates
- Moved inline CSS to external stylesheets for better maintainability
- Added caching mechanism for dashboard statistics queries (1 hour cache)
- Implemented pagination JavaScript handlers for AJAX navigation
- Added comprehensive error handling and logging throughout
- Fixed role-based access control (checking roles not capabilities)
- Improved performance with cached database queries
2025-08-21 20:41:59 -03:00

347 lines
No EOL
19 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/**
* Template Name: Trainer Dashboard
* Description: Template for the trainer dashboard page
*/
// Define constant to indicate we're in a page template
define('HVAC_IN_PAGE_TEMPLATE', true);
get_header();
?>
<div class="hvac-page-wrapper hvac-trainer-dashboard-page">
<?php
// Display trainer navigation menu
if (class_exists('HVAC_Menu_System')) {
HVAC_Menu_System::instance()->render_trainer_menu();
}
?>
<?php
// Display breadcrumbs
if (class_exists('HVAC_Breadcrumbs')) {
echo HVAC_Breadcrumbs::instance()->render_breadcrumbs();
}
?>
<div class="container">
<?php
// --- Security Check & Data Loading ---
// Ensure user is logged in and has access to the dashboard
if ( ! is_user_logged_in() ) {
// Redirect to login page if not logged in
wp_safe_redirect( home_url( '/training-login/' ) );
exit;
}
// Check if user has permission to view dashboard
// Check for HVAC trainer roles (not capabilities!)
$user = wp_get_current_user();
$has_trainer_role = in_array('hvac_trainer', $user->roles) || in_array('hvac_master_trainer', $user->roles);
if ( ! $has_trainer_role && ! current_user_can( 'manage_options' ) ) {
// Show access denied message instead of redirect to prevent loops
?>
<div class="hvac-access-denied">
<h1><?php _e('Access Denied', 'hvac-community-events'); ?></h1>
<p><?php _e('Sorry, you do not have permission to access the HVAC Trainer Dashboard.', 'hvac-community-events'); ?></p>
<p><?php _e('If you are an HVAC trainer, please contact an administrator to get the proper role assigned.', 'hvac-community-events'); ?></p>
<a href="<?php echo esc_url( home_url() ); ?>" class="button"><?php _e('Return to Home', 'hvac-community-events'); ?></a>
</div>
<?php
return;
}
// Get the current user ID
$user_id = get_current_user_id();
// Get dashboard data instance (class is autoloaded)
if (!class_exists('HVAC_Dashboard_Data')) {
require_once HVAC_PLUGIN_DIR . 'includes/class-hvac-dashboard-data.php';
}
$dashboard_data = new HVAC_Dashboard_Data( $user_id );
// Fetch data
$total_events = $dashboard_data->get_total_events_count();
$upcoming_events = $dashboard_data->get_upcoming_events_count();
$past_events = $dashboard_data->get_past_events_count();
$total_sold = $dashboard_data->get_total_tickets_sold();
$total_revenue = $dashboard_data->get_total_revenue();
$revenue_target = $dashboard_data->get_annual_revenue_target();
?>
<div class="hvac-dashboard-wrapper"> <!-- Dashboard specific wrapper -->
<!-- Dashboard Header -->
<div class="hvac-dashboard-header">
<h1 class="entry-title">Trainer Dashboard</h1> <!-- Standard WP title class -->
</div>
<!-- Statistics Section -->
<section class="hvac-dashboard-stats">
<?php echo HVAC_Help_System::add_tooltip(
'<h2>Your Stats</h2>',
'Overview of your event performance and revenue metrics',
'bottom'
); ?>
<div class="hvac-stats-row"> <!-- Use flexbox row layout -->
<!-- Stat Card: Total Events -->
<div class="hvac-stat-col"> <!-- Equal width flexbox column -->
<div class="hvac-stat-card">
<?php echo HVAC_Help_System::add_tooltip(
'<h3>Total Events</h3>',
'All events you\'ve created, including drafts and published events'
); ?>
<p class="metric-value"><?php echo esc_html( $total_events ); ?></p>
</div>
</div>
<!-- Stat Card: Upcoming Events -->
<div class="hvac-stat-col">
<div class="hvac-stat-card">
<?php echo HVAC_Help_System::add_tooltip(
'<h3>Upcoming Events</h3>',
'Published events scheduled for future dates'
); ?>
<p class="metric-value"><?php echo esc_html( $upcoming_events ); ?></p>
</div>
</div>
<!-- Stat Card: Past Events -->
<div class="hvac-stat-col">
<div class="hvac-stat-card">
<?php echo HVAC_Help_System::add_tooltip(
'<h3>Past Events</h3>',
'Completed events where you can generate certificates'
); ?>
<p class="metric-value"><?php echo esc_html( $past_events ); ?></p>
</div>
</div>
<!-- Stat Card: Total Tickets Sold -->
<div class="hvac-stat-col">
<div class="hvac-stat-card">
<?php echo HVAC_Help_System::add_tooltip(
'<h3>Tickets Sold</h3>',
'Total number of tickets sold across all your events'
); ?>
<p class="metric-value"><?php echo esc_html( $total_sold ); ?></p>
</div>
</div>
<!-- Stat Card: Total Revenue -->
<div class="hvac-stat-col">
<div class="hvac-stat-card">
<?php echo HVAC_Help_System::add_tooltip(
'<h3>Total Revenue</h3>',
'Total earnings from all ticket sales (before Stripe fees)'
); ?>
<p class="metric-value">$<?php echo esc_html( number_format( $total_revenue, 2 ) ); ?></p>
<?php if ( $revenue_target ) : ?>
<small>Target: $<?php echo esc_html( number_format( $revenue_target, 2 ) ); ?></small>
<?php endif; ?>
</div>
</div>
</div> <!-- /.ast-row -->
</section>
<!-- Events Table Section -->
<section class="hvac-dashboard-events">
<?php echo HVAC_Help_System::add_tooltip(
'<h2>Your Events</h2>',
'Detailed view of all your events with performance metrics and management options',
'bottom'
); ?>
<!-- Enhanced Filters and Controls -->
<div class="hvac-table-controls">
<!-- Search Box -->
<div class="hvac-search-box">
<?php echo HVAC_Help_System::add_tooltip(
'<input type="search" id="hvac-event-search" placeholder="Search events..." class="regular-text">',
'Search events by name'
); ?>
</div>
<!-- Date Range Filters -->
<div class="hvac-date-filters">
<label for="hvac-date-from">From:</label>
<input type="date" id="hvac-date-from" class="hvac-date-input">
<label for="hvac-date-to">To:</label>
<input type="date" id="hvac-date-to" class="hvac-date-input">
</div>
<!-- Per Page Selector -->
<div class="hvac-per-page">
<label for="hvac-per-page">Show:</label>
<select id="hvac-per-page" class="hvac-per-page-select">
<option value="10" selected>10</option>
<option value="25">25</option>
<option value="50">50</option>
<option value="100">100</option>
</select>
<span>per page</span>
</div>
</div>
<!-- Tab Filters -->
<?php
$dashboard_url = get_permalink(); // Get the current page URL
$current_filter = isset( $_GET['event_status'] ) ? sanitize_key( $_GET['event_status'] ) : 'all';
$filter_statuses = ['all', 'publish', 'draft', 'pending', 'private']; // Added private based on requirements/query
?>
<div class="hvac-event-filters">
<?php echo HVAC_Help_System::add_tooltip(
'<span>Filter: </span>',
'Filter events by their publication status'
); ?>
<?php foreach ($filter_statuses as $status) :
$url = add_query_arg( 'event_status', $status, $dashboard_url );
$class = 'ast-button ast-button-secondary hvac-filter';
if ($status === $current_filter) {
// Add a class or style for the active filter
// Using primary button style for active state as an example
$class = 'ast-button ast-button-primary hvac-filter hvac-filter-active';
}
// Special case for 'all' filter link
if ($status === 'all') {
$url = remove_query_arg( 'event_status', $dashboard_url );
}
?>
<a href="<?php echo esc_url( $url ); ?>" class="<?php echo esc_attr( $class ); ?>" data-status="<?php echo esc_attr( $status ); ?>"><?php echo esc_html( ucfirst( $status ) ); ?></a>
<?php endforeach; ?>
</div>
<!-- Events Table -->
<?php
// $current_filter is already defined above
// Get events with new parameters
$args = array(
'status' => $current_filter,
'search' => isset($_GET['search']) ? sanitize_text_field($_GET['search']) : '',
'orderby' => isset($_GET['orderby']) ? sanitize_key($_GET['orderby']) : 'date',
'order' => isset($_GET['order']) ? sanitize_key($_GET['order']) : 'DESC',
'page' => isset($_GET['paged']) ? absint($_GET['paged']) : 1,
'per_page' => isset($_GET['per_page']) ? absint($_GET['per_page']) : 10,
'date_from' => isset($_GET['date_from']) ? sanitize_text_field($_GET['date_from']) : '',
'date_to' => isset($_GET['date_to']) ? sanitize_text_field($_GET['date_to']) : ''
);
$result = $dashboard_data->get_events_table_data( $args );
$events = $result['events'];
$pagination = $result['pagination'];
?>
<div class="hvac-events-table-wrapper">
<table class="wp-list-table widefat fixed striped events-table">
<thead>
<tr>
<th scope="col" class="manage-column column-status">Status</th>
<th scope="col" class="manage-column column-title">Event Name</th>
<th scope="col" class="manage-column column-date">Date</th>
<th scope="col" class="manage-column column-organizer">Organizer</th>
<th scope="col" class="manage-column column-capacity">Capacity</th>
<th scope="col" class="manage-column column-sold">Sold</th>
<th scope="col" class="manage-column column-revenue">Revenue</th>
<th scope="col" class="manage-column column-actions">Actions</th> <!-- Added Actions Column -->
</tr>
</thead>
<tbody id="the-list">
<?php if ( ! empty( $events ) ) : ?>
<?php foreach ( $events as $event ) : ?>
<tr>
<td class="column-status"><?php echo esc_html( ucfirst( $event['status'] ) ); ?></td>
<td class="column-title">
<strong><a href="<?php echo esc_url( $event['link'] ); ?>" target="_blank"><?php echo esc_html( $event['name'] ); ?></a></strong>
<!-- Add Edit/View links below title if needed -->
</td>
<td class="column-date"><?php echo esc_html( date( 'Y-m-d H:i', $event['start_date_ts'] ) ); ?></td>
<td class="column-organizer"><?php
// Check if tribe_get_organizer function exists before calling
if ( function_exists( 'tribe_get_organizer' ) ) {
echo esc_html( tribe_get_organizer( $event['organizer_id'] ) );
} else {
echo 'Organizer ID: ' . esc_html( $event['organizer_id'] ); // Fallback
}
?></td>
<td class="column-capacity"><?php echo esc_html( $event['capacity'] ); ?></td>
<td class="column-sold"><?php echo esc_html( $event['sold'] ); ?></td>
<td class="column-revenue">$<?php echo esc_html( number_format( $event['revenue'], 2 ) ); ?></td>
<td class="column-actions">
<?php
// Link to the custom event edit form (no JavaScript dependencies!)
$edit_url = add_query_arg( 'event_id', $event['id'], home_url( '/trainer/event/edit/' ) );
// Link to the custom event summary page
$summary_url = add_query_arg( 'event_id', $event['id'], home_url( '/trainer/event/summary/' ) );
// Link to the standard WP single event view
$view_url = get_permalink( $event['id'] );
?>
<a href="<?php echo esc_url( $edit_url ); ?>">Edit</a> |
<a href="<?php echo esc_url( $summary_url ); ?>">Summary</a> |
<a href="<?php echo esc_url( $view_url ); ?>" target="_blank">View</a>
</td>
</tr>
<?php endforeach; ?>
<?php else : ?>
<tr>
<td colspan="8">No events found.</td> <!-- Updated colspan -->
</tr>
<?php endif; ?>
</tbody>
</table>
</div>
<div class="tablenav bottom">
<div class="tablenav-pages">
<span class="displaying-num"><?php echo esc_html($pagination['total_items']); ?> items</span>
<?php if ($pagination['total_pages'] > 1) : ?>
<span class="pagination-links">
<?php if ($pagination['has_prev']) : ?>
<a class="first-page button" href="#" data-page="1">
<span class="screen-reader-text">First page</span>
<span aria-hidden="true">«</span>
</a>
<a class="prev-page button" href="#" data-page="<?php echo esc_attr($pagination['current_page'] - 1); ?>">
<span class="screen-reader-text">Previous page</span>
<span aria-hidden="true"></span>
</a>
<?php else : ?>
<span class="tablenav-pages-navspan button disabled" aria-hidden="true">«</span>
<span class="tablenav-pages-navspan button disabled" aria-hidden="true"></span>
<?php endif; ?>
<span class="paging-input">
<label for="current-page-selector" class="screen-reader-text">Current Page</label>
<input class="current-page" id="current-page-selector" type="text" name="paged" value="<?php echo esc_attr($pagination['current_page']); ?>" size="1" aria-describedby="table-paging">
<span class="tablenav-paging-text"> of <span class="total-pages"><?php echo esc_html($pagination['total_pages']); ?></span></span>
</span>
<?php if ($pagination['has_next']) : ?>
<a class="next-page button" href="#" data-page="<?php echo esc_attr($pagination['current_page'] + 1); ?>">
<span class="screen-reader-text">Next page</span>
<span aria-hidden="true"></span>
</a>
<a class="last-page button" href="#" data-page="<?php echo esc_attr($pagination['total_pages']); ?>">
<span class="screen-reader-text">Last page</span>
<span aria-hidden="true">»</span>
</a>
<?php else : ?>
<span class="tablenav-pages-navspan button disabled" aria-hidden="true"></span>
<span class="tablenav-pages-navspan button disabled" aria-hidden="true">»</span>
<?php endif; ?>
</span>
</div>
</div>
<?php endif; ?>
</section>
</div> <!-- .hvac-dashboard-wrapper -->
</div>
</div>
<?php
get_footer();