upskill-event-manager/includes/class-hvac-announcements-manager.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

327 lines
No EOL
9.9 KiB
PHP

<?php
/**
* HVAC Announcements Manager
*
* @package HVAC_Community_Events
* @since 1.0.0
*/
if (!defined('ABSPATH')) {
exit;
}
/**
* Class HVAC_Announcements_Manager
*
* Main orchestrator for the announcements system
*/
class HVAC_Announcements_Manager {
/**
* Instance of this class
*
* @var HVAC_Announcements_Manager
*/
private static $instance = null;
/**
* Component instances
*
* @var array
*/
private $components = array();
/**
* Get instance of this class
*
* @return HVAC_Announcements_Manager
*/
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor
*/
private function __construct() {
$this->load_dependencies();
$this->init_components();
$this->init_hooks();
}
/**
* Load required files
*/
private function load_dependencies() {
$base_path = plugin_dir_path(dirname(__FILE__)) . 'includes/';
// Load component classes
require_once $base_path . 'class-hvac-announcements-cpt.php';
require_once $base_path . 'class-hvac-announcements-permissions.php';
require_once $base_path . 'class-hvac-announcements-ajax.php';
require_once $base_path . 'class-hvac-announcements-email.php';
require_once $base_path . 'class-hvac-announcements-display.php';
}
/**
* Initialize components
*/
private function init_components() {
$this->components['cpt'] = HVAC_Announcements_CPT::get_instance();
$this->components['permissions'] = HVAC_Announcements_Permissions::get_instance();
$this->components['ajax'] = HVAC_Announcements_Ajax::get_instance();
$this->components['email'] = HVAC_Announcements_Email::get_instance();
$this->components['display'] = HVAC_Announcements_Display::get_instance();
}
/**
* Initialize hooks
*/
private function init_hooks() {
// Activation/deactivation hooks
register_activation_hook(HVAC_PLUGIN_FILE, array($this, 'activate'));
register_deactivation_hook(HVAC_PLUGIN_FILE, array($this, 'deactivate'));
// Page creation
add_action('init', array($this, 'maybe_create_pages'), 20);
// Scripts and styles
add_action('wp_enqueue_scripts', array($this, 'enqueue_frontend_assets'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_assets'));
// Add to plugin's script management
add_filter('hvac_plugin_page_slugs', array($this, 'add_page_slugs'));
}
/**
* Plugin activation
*/
public function activate() {
// Add capabilities
HVAC_Announcements_Permissions::add_capabilities();
// Create pages
$this->create_pages();
// Flush rewrite rules
flush_rewrite_rules();
}
/**
* Plugin deactivation
*/
public function deactivate() {
// Remove capabilities (optional - you might want to keep them)
// HVAC_Announcements_Permissions::remove_capabilities();
// Flush rewrite rules
flush_rewrite_rules();
}
/**
* Create required pages
*/
private function create_pages() {
$pages = array(
array(
'title' => 'Announcements',
'slug' => 'master-announcements',
'parent_slug' => 'master-dashboard',
'template' => 'templates/page-master-announcements.php',
'meta_key' => '_hvac_page_master_announcements_created',
),
array(
'title' => 'Resources',
'slug' => 'trainer-resources',
'parent_slug' => 'dashboard',
'template' => 'templates/page-trainer-resources.php',
'meta_key' => '_hvac_page_trainer_resources_created',
),
);
foreach ($pages as $page_data) {
// Check if page was already created
if (get_option($page_data['meta_key'])) {
continue;
}
// Find parent page
$parent_id = 0;
if (!empty($page_data['parent_slug'])) {
$parent_page = get_page_by_path($page_data['parent_slug']);
if ($parent_page) {
$parent_id = $parent_page->ID;
}
}
// Create page
$page_id = wp_insert_post(array(
'post_title' => $page_data['title'],
'post_name' => $page_data['slug'],
'post_content' => '',
'post_status' => 'publish',
'post_type' => 'page',
'post_parent' => $parent_id,
'meta_input' => array(
'_wp_page_template' => $page_data['template'],
),
));
if (!is_wp_error($page_id)) {
update_option($page_data['meta_key'], $page_id);
}
}
}
/**
* Maybe create pages if they don't exist
*/
public function maybe_create_pages() {
// Check if pages exist
$master_page = get_page_by_path('master-trainer/master-announcements');
$resources_page = get_page_by_path('trainer/trainer-resources');
if (!$master_page || !$resources_page) {
$this->create_pages();
}
}
/**
* Add announcement page slugs to plugin pages list
*
* @param array $slugs Existing page slugs
* @return array
*/
public function add_page_slugs($slugs) {
$slugs[] = 'master-announcements';
$slugs[] = 'trainer-resources';
return $slugs;
}
/**
* Enqueue frontend assets
*/
public function enqueue_frontend_assets() {
// Check if we're on a relevant page
if (!$this->is_announcement_page()) {
return;
}
// Enqueue styles
wp_enqueue_style(
'hvac-announcements',
plugin_dir_url(dirname(__FILE__)) . 'assets/css/hvac-announcements.css',
array(),
HVAC_VERSION
);
// Enqueue view script for trainer resources page
if (is_page('trainer-resources') || strpos(home_url($GLOBALS['wp']->request), '/trainer/resources') !== false) {
wp_enqueue_script(
'hvac-announcements-view',
plugin_dir_url(dirname(__FILE__)) . 'assets/js/hvac-announcements-view.js',
array('jquery'),
HVAC_VERSION,
true
);
// Localize script for viewing
wp_localize_script('hvac-announcements-view', 'hvac_ajax', array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('hvac_announcements_nonce'),
));
}
// Enqueue scripts for master announcements page
if (is_page('master-announcements')) {
wp_enqueue_script(
'hvac-announcements-admin',
plugin_dir_url(dirname(__FILE__)) . 'assets/js/hvac-announcements-admin.js',
array('jquery', 'wp-util'),
HVAC_VERSION,
true
);
// Add TinyMCE
wp_enqueue_editor();
// Add media uploader
wp_enqueue_media();
// Localize script
wp_localize_script('hvac-announcements-admin', 'hvac_announcements', array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('hvac_announcements_nonce'),
'strings' => array(
'confirm_delete' => __('Are you sure you want to delete this announcement?', 'hvac'),
'error_loading' => __('Error loading announcements', 'hvac'),
'error_saving' => __('Error saving announcement', 'hvac'),
'success_created' => __('Announcement created successfully', 'hvac'),
'success_updated' => __('Announcement updated successfully', 'hvac'),
'success_deleted' => __('Announcement deleted successfully', 'hvac'),
),
));
}
}
/**
* Enqueue admin assets
*/
public function enqueue_admin_assets($hook) {
// Only load on our custom pages
if (!$this->is_announcement_page()) {
return;
}
// Admin styles
wp_enqueue_style(
'hvac-announcements-admin',
plugin_dir_url(dirname(__FILE__)) . 'assets/css/hvac-announcements-admin.css',
array(),
HVAC_VERSION
);
}
/**
* Check if current page is an announcement-related page
*
* @return bool
*/
private function is_announcement_page() {
if (is_page('master-announcements') || is_page('trainer-resources')) {
return true;
}
// Check for hierarchical URLs
global $wp;
$current_url = home_url($wp->request);
if (strpos($current_url, '/master-trainer/announcements') !== false ||
strpos($current_url, '/trainer/resources') !== false) {
return true;
}
return false;
}
/**
* Get component instance
*
* @param string $component Component name
* @return object|null
*/
public function get_component($component) {
return isset($this->components[$component]) ? $this->components[$component] : null;
}
/**
* Initialize the announcements system
* Called from main plugin file
*/
public static function init() {
return self::get_instance();
}
}