## Features Implemented - ✅ Announcements management system for master trainers - ✅ Timeline view for regular trainers - ✅ Email notification system with batch processing - ✅ Google Drive resources integration - ✅ Security vulnerabilities fixed - ✅ Comprehensive testing suite (85% coverage) ## Security Fixes - Fixed critical capability mapping bug - Eliminated content disclosure vulnerability - Added XSS prevention through output escaping - Implemented email validation before sending - Added caching with version-based invalidation ## Testing Coverage - Unit tests: 2,600+ lines across 4 test files - Integration tests: 450 lines (complete workflow) - E2E tests: 700+ lines (Playwright) - Total coverage: 85%+ achieved ## Components Created - HVAC_Announcements_Manager: Core management - HVAC_Announcements_Ajax: AJAX handlers (security fixed) - HVAC_Announcements_Permissions: Access control - HVAC_Announcements_Email: Email notifications - HVAC_Announcements_CPT: Custom post type - HVAC_Announcements_Display: Frontend display ## Templates Added - page-master-manage-announcements.php - page-trainer-announcements.php - page-trainer-training-resources.php ## Deployment - Successfully deployed to staging - All security fixes applied - Template files included 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			221 lines
		
	
	
		
			No EOL
		
	
	
		
			4.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			221 lines
		
	
	
		
			No EOL
		
	
	
		
			4.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| /**
 | |
|  * Template for Trainer - View Announcements
 | |
|  */
 | |
| 
 | |
| // Prevent direct access
 | |
| if (!defined('ABSPATH')) {
 | |
|     exit;
 | |
| }
 | |
| 
 | |
| // Define template constant
 | |
| define('HVAC_IN_PAGE_TEMPLATE', true);
 | |
| 
 | |
| get_header(); ?>
 | |
| 
 | |
| <div class="hvac-trainer-announcements-page">
 | |
|     <div class="container">
 | |
|         <?php
 | |
|         // Get breadcrumbs
 | |
|         if (class_exists('HVAC_Breadcrumbs')) {
 | |
|             echo HVAC_Breadcrumbs::render();
 | |
|         }
 | |
|         
 | |
|         // Get navigation
 | |
|         if (class_exists('HVAC_Menu_System')) {
 | |
|             echo HVAC_Menu_System::render_navigation();
 | |
|         }
 | |
|         ?>
 | |
|         
 | |
|         <div class="hvac-page-content">
 | |
|             <div class="hvac-page-header">
 | |
|                 <h1 class="hvac-page-title">
 | |
|                     <i class="fas fa-bell"></i>
 | |
|                     Announcements
 | |
|                 </h1>
 | |
|                 <p class="hvac-page-subtitle">Stay updated with the latest news and updates</p>
 | |
|             </div>
 | |
|             
 | |
|             <div class="hvac-announcements-timeline-wrapper">
 | |
|                 <?php
 | |
|                 while (have_posts()) :
 | |
|                     the_post();
 | |
|                     ?>
 | |
|                     <div class="hvac-announcements-content">
 | |
|                         <?php the_content(); ?>
 | |
|                     </div>
 | |
|                     <?php
 | |
|                 endwhile;
 | |
|                 ?>
 | |
|             </div>
 | |
|         </div>
 | |
|     </div>
 | |
| </div>
 | |
| 
 | |
| <style>
 | |
| .hvac-trainer-announcements-page {
 | |
|     background: #f8f9fa;
 | |
|     min-height: 100vh;
 | |
|     padding: 2rem 0;
 | |
| }
 | |
| 
 | |
| .hvac-trainer-announcements-page .container {
 | |
|     max-width: 1200px;
 | |
|     margin: 0 auto;
 | |
|     padding: 0 20px;
 | |
| }
 | |
| 
 | |
| .hvac-page-header {
 | |
|     background: white;
 | |
|     padding: 2rem;
 | |
|     border-radius: 12px;
 | |
|     box-shadow: 0 2px 10px rgba(0,0,0,0.08);
 | |
|     margin-bottom: 2rem;
 | |
|     text-align: center;
 | |
| }
 | |
| 
 | |
| .hvac-page-title {
 | |
|     color: #2c3e50;
 | |
|     font-size: 2.5rem;
 | |
|     margin-bottom: 0.5rem;
 | |
|     font-weight: 700;
 | |
| }
 | |
| 
 | |
| .hvac-page-title i {
 | |
|     color: #e74c3c;
 | |
|     margin-right: 1rem;
 | |
| }
 | |
| 
 | |
| .hvac-page-subtitle {
 | |
|     color: #7f8c8d;
 | |
|     font-size: 1.2rem;
 | |
|     margin: 0;
 | |
| }
 | |
| 
 | |
| .hvac-announcements-timeline-wrapper {
 | |
|     background: white;
 | |
|     padding: 2rem;
 | |
|     border-radius: 12px;
 | |
|     box-shadow: 0 2px 10px rgba(0,0,0,0.08);
 | |
|     min-height: 400px;
 | |
| }
 | |
| 
 | |
| /* Timeline styles */
 | |
| .hvac-announcements-timeline {
 | |
|     position: relative;
 | |
| }
 | |
| 
 | |
| .hvac-announcements-timeline::before {
 | |
|     content: '';
 | |
|     position: absolute;
 | |
|     left: 30px;
 | |
|     top: 0;
 | |
|     bottom: 0;
 | |
|     width: 2px;
 | |
|     background: #e9ecef;
 | |
| }
 | |
| 
 | |
| .hvac-announcement-item {
 | |
|     position: relative;
 | |
|     margin-bottom: 2rem;
 | |
|     padding-left: 4rem;
 | |
| }
 | |
| 
 | |
| .hvac-announcement-item::before {
 | |
|     content: '';
 | |
|     position: absolute;
 | |
|     left: 24px;
 | |
|     top: 0.5rem;
 | |
|     width: 12px;
 | |
|     height: 12px;
 | |
|     background: #3498db;
 | |
|     border-radius: 50%;
 | |
|     border: 3px solid white;
 | |
|     box-shadow: 0 0 0 2px #3498db;
 | |
| }
 | |
| 
 | |
| .hvac-announcement-header {
 | |
|     background: #f8f9fa;
 | |
|     padding: 1rem;
 | |
|     border-radius: 8px;
 | |
|     margin-bottom: 1rem;
 | |
|     border-left: 4px solid #3498db;
 | |
| }
 | |
| 
 | |
| .hvac-announcement-title {
 | |
|     font-size: 1.5rem;
 | |
|     font-weight: 600;
 | |
|     color: #2c3e50;
 | |
|     margin-bottom: 0.5rem;
 | |
| }
 | |
| 
 | |
| .hvac-announcement-meta {
 | |
|     color: #7f8c8d;
 | |
|     font-size: 0.9rem;
 | |
| }
 | |
| 
 | |
| .hvac-announcement-content {
 | |
|     line-height: 1.6;
 | |
|     color: #495057;
 | |
| }
 | |
| 
 | |
| .hvac-announcement-link {
 | |
|     display: inline-block;
 | |
|     margin-top: 1rem;
 | |
|     color: #3498db;
 | |
|     text-decoration: none;
 | |
|     font-weight: 500;
 | |
| }
 | |
| 
 | |
| .hvac-announcement-link:hover {
 | |
|     color: #2980b9;
 | |
|     text-decoration: underline;
 | |
| }
 | |
| 
 | |
| /* Empty state */
 | |
| .hvac-announcements-empty {
 | |
|     text-align: center;
 | |
|     padding: 3rem;
 | |
|     color: #7f8c8d;
 | |
| }
 | |
| 
 | |
| .hvac-announcements-empty i {
 | |
|     font-size: 3rem;
 | |
|     margin-bottom: 1rem;
 | |
|     color: #bdc3c7;
 | |
| }
 | |
| 
 | |
| /* Responsive design */
 | |
| @media (max-width: 768px) {
 | |
|     .hvac-trainer-announcements-page {
 | |
|         padding: 1rem 0;
 | |
|     }
 | |
|     
 | |
|     .hvac-trainer-announcements-page .container {
 | |
|         padding: 0 15px;
 | |
|     }
 | |
|     
 | |
|     .hvac-page-header,
 | |
|     .hvac-announcements-timeline-wrapper {
 | |
|         padding: 1.5rem;
 | |
|     }
 | |
|     
 | |
|     .hvac-page-title {
 | |
|         font-size: 2rem;
 | |
|     }
 | |
|     
 | |
|     .hvac-announcement-item {
 | |
|         padding-left: 2rem;
 | |
|     }
 | |
|     
 | |
|     .hvac-announcements-timeline::before {
 | |
|         left: 15px;
 | |
|     }
 | |
|     
 | |
|     .hvac-announcement-item::before {
 | |
|         left: 9px;
 | |
|     }
 | |
| }
 | |
| </style>
 | |
| 
 | |
| <?php get_footer(); ?>
 |