upskill-event-manager/templates/page-master-announcements.php
Ben c20b461e7d feat: Implement secure Trainer Announcements system with comprehensive features
This commit introduces a complete announcement management system for HVAC trainers
with enterprise-grade security, performance optimization, and email notifications.

## Core Features
- Custom post type for trainer announcements with categories and tags
- Role-based permissions (master trainers can create/edit, all trainers can read)
- AJAX-powered admin interface with real-time updates
- Modal popup viewing for announcements on frontend
- Automated email notifications when announcements are published
- Google Drive integration for training resources

## Security Enhancements
- Fixed critical capability mapping bug preventing proper permission checks
- Added content disclosure protection for draft/private announcements
- Fixed XSS vulnerabilities with proper output escaping and sanitization
- Implemented permission checks on all AJAX endpoints
- Added rate limiting to prevent abuse (30 requests/minute)
- Email validation before sending notifications

## Performance Optimizations
- Implemented intelligent caching for user queries (5-minute TTL)
- Added cache versioning for announcement lists (2-minute TTL)
- Automatic cache invalidation on content changes
- Batch email processing to prevent timeouts (50 emails per batch)
- Retry mechanism for failed email sends (max 3 attempts)

## Technical Implementation
- Singleton pattern for all manager classes
- WordPress coding standards compliance
- Proper nonce verification on all AJAX requests
- Comprehensive error handling and logging
- Mobile-responsive UI with smooth animations
- WCAG accessibility compliance

## Components Added
- 6 PHP classes for modular architecture
- 2 page templates (master announcements, trainer resources)
- Admin and frontend JavaScript with jQuery integration
- Comprehensive CSS for both admin and frontend
- Email notification system with HTML templates
- Complete documentation and implementation plans

This system provides a secure, scalable foundation for trainer communications
while following WordPress best practices and maintaining high code quality.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-20 13:34:15 -03:00

194 lines
No EOL
8.9 KiB
PHP

<?php
/**
* Template Name: Master Trainer Announcements
* Description: Manage trainer announcements (Master Trainers only)
*
* @package HVAC_Community_Events
*/
// Security check
if (!defined('ABSPATH')) {
exit;
}
// Define template constant
if (!defined('HVAC_IN_PAGE_TEMPLATE')) {
define('HVAC_IN_PAGE_TEMPLATE', true);
}
// Check if user is a master trainer
if (!HVAC_Announcements_Permissions::is_master_trainer()) {
wp_redirect(home_url('/trainer/dashboard/'));
exit;
}
get_header();
// Get menu system instance
$menu_system = HVAC_Menu_System::get_instance();
?>
<div class="hvac-plugin-page hvac-master-announcements-page">
<?php
// Display navigation menu
echo $menu_system->render_navigation_menu();
?>
<!-- Breadcrumbs -->
<nav class="hvac-breadcrumbs" aria-label="Breadcrumb">
<div class="container">
<ol class="breadcrumb-list">
<li class="breadcrumb-item"><a href="<?php echo home_url(); ?>">Home</a></li>
<li class="breadcrumb-item"><a href="<?php echo home_url('/master-trainer/master-dashboard/'); ?>">Master Dashboard</a></li>
<li class="breadcrumb-item active" aria-current="page">Announcements</li>
</ol>
</div>
</nav>
<div class="container">
<div class="hvac-announcements-wrapper">
<header class="page-header">
<h1><?php _e('Trainer Announcements', 'hvac'); ?></h1>
<button id="add-announcement-btn" class="button button-primary">
<span class="dashicons dashicons-plus-alt"></span>
<?php _e('Add New Announcement', 'hvac'); ?>
</button>
</header>
<!-- Filters and Search -->
<div class="announcements-controls">
<div class="filter-group">
<label for="status-filter"><?php _e('Status:', 'hvac'); ?></label>
<select id="status-filter" class="filter-select">
<option value="any"><?php _e('All', 'hvac'); ?></option>
<option value="publish"><?php _e('Published', 'hvac'); ?></option>
<option value="draft"><?php _e('Draft', 'hvac'); ?></option>
<option value="private"><?php _e('Private', 'hvac'); ?></option>
</select>
</div>
<div class="search-group">
<input type="text" id="announcement-search" placeholder="<?php esc_attr_e('Search announcements...', 'hvac'); ?>" />
<button id="search-btn" class="button">
<span class="dashicons dashicons-search"></span>
</button>
</div>
</div>
<!-- Announcements Table -->
<div class="announcements-table-wrapper">
<table id="announcements-table" class="wp-list-table widefat fixed striped">
<thead>
<tr>
<th class="column-title"><?php _e('Title', 'hvac'); ?></th>
<th class="column-status"><?php _e('Status', 'hvac'); ?></th>
<th class="column-categories"><?php _e('Categories', 'hvac'); ?></th>
<th class="column-author"><?php _e('Author', 'hvac'); ?></th>
<th class="column-date"><?php _e('Date', 'hvac'); ?></th>
<th class="column-actions"><?php _e('Actions', 'hvac'); ?></th>
</tr>
</thead>
<tbody id="announcements-list">
<!-- Populated via AJAX -->
</tbody>
</table>
<!-- Pagination -->
<div class="announcements-pagination">
<button id="prev-page" class="button" disabled>
<span class="dashicons dashicons-arrow-left-alt2"></span>
<?php _e('Previous', 'hvac'); ?>
</button>
<span class="page-info">
<?php _e('Page', 'hvac'); ?> <span id="current-page">1</span> <?php _e('of', 'hvac'); ?> <span id="total-pages">1</span>
</span>
<button id="next-page" class="button">
<?php _e('Next', 'hvac'); ?>
<span class="dashicons dashicons-arrow-right-alt2"></span>
</button>
</div>
</div>
</div>
</div>
<!-- Add/Edit Announcement Modal -->
<div id="announcement-modal" class="hvac-modal" style="display: none;">
<div class="modal-content">
<div class="modal-header">
<h2 id="modal-title"><?php _e('Add New Announcement', 'hvac'); ?></h2>
<button class="modal-close">&times;</button>
</div>
<form id="announcement-form">
<div class="modal-body">
<input type="hidden" id="announcement-id" value="" />
<div class="form-group">
<label for="announcement-title"><?php _e('Title', 'hvac'); ?> <span class="required">*</span></label>
<input type="text" id="announcement-title" name="title" required />
</div>
<div class="form-group">
<label for="announcement-content"><?php _e('Content', 'hvac'); ?></label>
<div id="announcement-content-editor"></div>
<textarea id="announcement-content" name="content" style="display: none;"></textarea>
</div>
<div class="form-group">
<label for="announcement-excerpt"><?php _e('Excerpt', 'hvac'); ?></label>
<textarea id="announcement-excerpt" name="excerpt" rows="3"></textarea>
</div>
<div class="form-row">
<div class="form-group">
<label for="announcement-status"><?php _e('Status', 'hvac'); ?></label>
<select id="announcement-status" name="status">
<option value="draft"><?php _e('Draft', 'hvac'); ?></option>
<option value="publish"><?php _e('Published', 'hvac'); ?></option>
<option value="private"><?php _e('Private', 'hvac'); ?></option>
</select>
</div>
<div class="form-group">
<label for="announcement-date"><?php _e('Publish Date', 'hvac'); ?></label>
<input type="datetime-local" id="announcement-date" name="publish_date" />
</div>
</div>
<div class="form-group">
<label for="announcement-categories"><?php _e('Categories', 'hvac'); ?></label>
<div id="categories-container">
<!-- Populated via AJAX -->
</div>
</div>
<div class="form-group">
<label for="announcement-tags"><?php _e('Tags', 'hvac'); ?></label>
<input type="text" id="announcement-tags" name="tags" placeholder="<?php esc_attr_e('Separate tags with commas', 'hvac'); ?>" />
</div>
<div class="form-group">
<label><?php _e('Featured Image', 'hvac'); ?></label>
<div class="featured-image-container">
<div id="featured-image-preview"></div>
<button type="button" id="select-featured-image" class="button">
<?php _e('Select Image', 'hvac'); ?>
</button>
<button type="button" id="remove-featured-image" class="button" style="display: none;">
<?php _e('Remove Image', 'hvac'); ?>
</button>
<input type="hidden" id="featured-image-id" name="featured_image_id" />
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="button modal-cancel"><?php _e('Cancel', 'hvac'); ?></button>
<button type="submit" class="button button-primary"><?php _e('Save Announcement', 'hvac'); ?></button>
</div>
</form>
</div>
</div>
</div>
<?php get_footer(); ?>