Address top 3 critical issues preventing dashboard content from rendering: 1. HTML Injection Fix (class-hvac-community-events.php:924-927): - Move error div from wp_head to wp_footer with proper styling - Prevent markup corruption that breaks content rendering - Add proper escaping with esc_html() 2. Remove Template Redundancy (class-hvac-community-events.php): - Remove force_master_dashboard_content() method and filter - Eliminate competing content injection mechanisms - Simplify to single template_include approach 3. Navigation System Integration (class-hvac-master-menu-system.php): - Align DOM IDs with existing JavaScript expectations - Change wrapper classes to match existing CSS hooks - Fix capability vs role filtering logic 4. Template Safety (page-master-dashboard.php): - Guard constant definition to prevent redefinition notices These fixes resolve zen GPT-5 identified issues: - [CRITICAL] HTML in wp_head breaking content display - [HIGH] Redundant template mechanisms causing conflicts - [HIGH] CSS/JS integration mismatches preventing navigation - [MEDIUM] Capability filtering using role names incorrectly Architecture improvements maintain security while fixing execution. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			360 lines
		
	
	
		
			No EOL
		
	
	
		
			12 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			360 lines
		
	
	
		
			No EOL
		
	
	
		
			12 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| /**
 | |
|  * HVAC Master Trainer Menu System
 | |
|  *
 | |
|  * Handles navigation menus specifically for master trainer pages
 | |
|  *
 | |
|  * @package HVAC_Community_Events
 | |
|  * @since 1.0.0
 | |
|  */
 | |
| 
 | |
| if (!defined('ABSPATH')) {
 | |
|     exit;
 | |
| }
 | |
| 
 | |
| class HVAC_Master_Menu_System {
 | |
|     
 | |
|     /**
 | |
|      * Instance of this class
 | |
|      *
 | |
|      * @var HVAC_Master_Menu_System
 | |
|      */
 | |
|     private static $instance = null;
 | |
|     
 | |
|     /**
 | |
|      * Get instance of this class
 | |
|      *
 | |
|      * @return HVAC_Master_Menu_System
 | |
|      */
 | |
|     public static function instance() {
 | |
|         if (self::$instance === null) {
 | |
|             self::$instance = new self();
 | |
|         }
 | |
|         return self::$instance;
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Constructor
 | |
|      */
 | |
|     private function __construct() {
 | |
|         // No auto-init hooks - will be called manually on master pages
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Check if current page is a master trainer page
 | |
|      * 
 | |
|      * @return bool
 | |
|      */
 | |
|     public function is_master_trainer_page() {
 | |
|         $current_url = $_SERVER['REQUEST_URI'];
 | |
|         
 | |
|         // List of master trainer page patterns
 | |
|         $master_pages = array(
 | |
|             '/master-trainer/master-dashboard/',
 | |
|             '/master-trainer/announcements/',
 | |
|             '/master-trainer/edit-trainer-profile/',
 | |
|             '/master-trainer/communication-templates/',
 | |
|             '/master-trainer/google-sheets/',
 | |
|             '/master-trainer/trainers/',
 | |
|             '/master-trainer/pending-approvals/',
 | |
|             '/master-trainer/trainer-stats/',
 | |
|             '/master-trainer/import-export/'
 | |
|         );
 | |
|         
 | |
|         foreach ($master_pages as $page) {
 | |
|             if (strpos($current_url, $page) !== false) {
 | |
|                 return true;
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         return false;
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Render master trainer navigation menu
 | |
|      */
 | |
|     public function render_master_menu() {
 | |
|         // Check if user has master trainer permissions
 | |
|         $user = wp_get_current_user();
 | |
|         if (!in_array('hvac_master_trainer', $user->roles) && !current_user_can('manage_options')) {
 | |
|             return;
 | |
|         }
 | |
|         
 | |
|         $menu_items = $this->get_master_menu_structure();
 | |
|         
 | |
|         echo '<div class="hvac-trainer-menu-wrapper">';
 | |
|         echo '<nav class="hvac-trainer-nav" role="navigation">';
 | |
|         
 | |
|         // Add hamburger button for mobile
 | |
|         echo '<button class="hvac-hamburger-menu" id="hvac-hamburger-menu" aria-label="Toggle menu" aria-expanded="false">';
 | |
|         echo '<span class="hvac-hamburger-line"></span>';
 | |
|         echo '<span class="hvac-hamburger-line"></span>';
 | |
|         echo '<span class="hvac-hamburger-line"></span>';
 | |
|         echo '</button>';
 | |
|         
 | |
|         echo '<ul class="hvac-trainer-menu" id="hvac-trainer-menu">';
 | |
|         
 | |
|         foreach ($menu_items as $item) {
 | |
|             $this->render_menu_item($item);
 | |
|         }
 | |
|         
 | |
|         echo '</ul>';
 | |
|         echo '</nav>';
 | |
|         echo '</div>';
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Get master trainer menu structure
 | |
|      * Simplified to 5 essential items following UX best practices
 | |
|      */
 | |
|     private function get_master_menu_structure() {
 | |
|         // Define simplified menu structure (5 primary items max)
 | |
|         $menu = array(
 | |
|             // Dashboard - Primary landing page
 | |
|             array(
 | |
|                 'title' => esc_html__('Dashboard', 'hvac-community-events'),
 | |
|                 'url' => home_url('/master-trainer/master-dashboard/'),
 | |
|                 'icon' => 'dashicons-dashboard',
 | |
|                 'cap' => 'hvac_master_trainer'
 | |
|             ),
 | |
|             
 | |
|             // Trainers - Core management function
 | |
|             array(
 | |
|                 'title' => esc_html__('Trainers', 'hvac-community-events'),
 | |
|                 'url' => home_url('/master-trainer/trainers/'),
 | |
|                 'icon' => 'dashicons-groups',
 | |
|                 'cap' => 'hvac_master_trainer',
 | |
|                 'children' => array(
 | |
|                     array(
 | |
|                         'title' => esc_html__('All Trainers', 'hvac-community-events'),
 | |
|                         'url' => home_url('/master-trainer/trainers/'),
 | |
|                         'icon' => 'dashicons-list-view',
 | |
|                         'cap' => 'hvac_master_trainer'
 | |
|                     ),
 | |
|                     array(
 | |
|                         'title' => esc_html__('Pending Approvals', 'hvac-community-events'),
 | |
|                         'url' => home_url('/master-trainer/pending-approvals/'),
 | |
|                         'icon' => 'dashicons-clock',
 | |
|                         'cap' => 'approve_trainers'
 | |
|                     )
 | |
|                 )
 | |
|             ),
 | |
|             
 | |
|             // Events - Aggregate event management
 | |
|             array(
 | |
|                 'title' => esc_html__('Events', 'hvac-community-events'),
 | |
|                 'url' => home_url('/master-trainer/events/'),
 | |
|                 'icon' => 'dashicons-calendar-alt',
 | |
|                 'cap' => 'view_all_events'
 | |
|             ),
 | |
|             
 | |
|             // Tools - Administrative functions
 | |
|             array(
 | |
|                 'title' => esc_html__('Tools', 'hvac-community-events'),
 | |
|                 'url' => home_url('/master-trainer/communication-templates/'),
 | |
|                 'icon' => 'dashicons-admin-tools',
 | |
|                 'cap' => 'manage_communication_templates',
 | |
|                 'children' => array(
 | |
|                     array(
 | |
|                         'title' => esc_html__('Communication Templates', 'hvac-community-events'),
 | |
|                         'url' => home_url('/master-trainer/communication-templates/'),
 | |
|                         'icon' => 'dashicons-email',
 | |
|                         'cap' => 'manage_communication_templates'
 | |
|                     ),
 | |
|                     array(
 | |
|                         'title' => esc_html__('Announcements', 'hvac-community-events'),
 | |
|                         'url' => home_url('/master-trainer/announcements/'),
 | |
|                         'icon' => 'dashicons-megaphone',
 | |
|                         'cap' => 'manage_announcements'
 | |
|                     ),
 | |
|                     array(
 | |
|                         'title' => esc_html__('Import/Export', 'hvac-community-events'),
 | |
|                         'url' => home_url('/master-trainer/import-export/'),
 | |
|                         'icon' => 'dashicons-database-import',
 | |
|                         'cap' => 'import_export_data'
 | |
|                     )
 | |
|                 )
 | |
|             ),
 | |
|             
 | |
|             // Help - Documentation
 | |
|             array(
 | |
|                 'title' => esc_html__('Help', 'hvac-community-events'),
 | |
|                 'url' => home_url('/trainer/documentation/'),
 | |
|                 'icon' => 'dashicons-editor-help',
 | |
|                 'cap' => 'read',
 | |
|                 'class' => 'hvac-help-menu-item'
 | |
|             )
 | |
|         );
 | |
|         
 | |
|         // Allow other plugins to modify menu
 | |
|         $menu = apply_filters('hvac_master_menu_items', $menu);
 | |
|         
 | |
|         // Filter menu items by user capabilities
 | |
|         $menu = $this->filter_menu_by_capabilities($menu);
 | |
|         
 | |
|         return $menu;
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Filter menu items by user capabilities
 | |
|      * Removes items the current user cannot access
 | |
|      *
 | |
|      * @param array $menu_items Menu items array
 | |
|      * @return array Filtered menu items
 | |
|      */
 | |
|     private function filter_menu_by_capabilities($menu_items) {
 | |
|         $filtered_menu = array();
 | |
|         
 | |
|         foreach ($menu_items as $item) {
 | |
|             // Check if user has capability for this item
 | |
|             $required_cap = isset($item['cap']) ? $item['cap'] : 'hvac_master_trainer';
 | |
|             
 | |
|             // Handle role names vs capabilities properly
 | |
|             $user = wp_get_current_user();
 | |
|             $has_access = false;
 | |
|             
 | |
|             if ($required_cap === 'hvac_master_trainer') {
 | |
|                 $has_access = in_array('hvac_master_trainer', (array) $user->roles, true) || current_user_can('manage_options');
 | |
|             } else {
 | |
|                 $has_access = current_user_can($required_cap);
 | |
|             }
 | |
|             
 | |
|             if (!$has_access) {
 | |
|                 continue; // Skip this item
 | |
|             }
 | |
|             
 | |
|             // Filter children if they exist
 | |
|             if (isset($item['children']) && is_array($item['children'])) {
 | |
|                 $filtered_children = array();
 | |
|                 
 | |
|                 foreach ($item['children'] as $child) {
 | |
|                     $child_cap = isset($child['cap']) ? $child['cap'] : 'hvac_master_trainer';
 | |
|                     
 | |
|                     // Handle role names vs capabilities properly for children too
 | |
|                     $has_child_access = false;
 | |
|                     if ($child_cap === 'hvac_master_trainer') {
 | |
|                         $has_child_access = in_array('hvac_master_trainer', (array) $user->roles, true) || current_user_can('manage_options');
 | |
|                     } else {
 | |
|                         $has_child_access = current_user_can($child_cap);
 | |
|                     }
 | |
|                     
 | |
|                     if ($has_child_access) {
 | |
|                         $filtered_children[] = $child;
 | |
|                     }
 | |
|                 }
 | |
|                 
 | |
|                 // Only include parent if it has accessible children or is directly accessible
 | |
|                 if (!empty($filtered_children)) {
 | |
|                     $item['children'] = $filtered_children;
 | |
|                     $filtered_menu[] = $item;
 | |
|                 } elseif (!isset($item['children']) || empty($item['children'])) {
 | |
|                     // Include parent items without children
 | |
|                     $filtered_menu[] = $item;
 | |
|                 }
 | |
|             } else {
 | |
|                 // Include items without children
 | |
|                 $filtered_menu[] = $item;
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         return $filtered_menu;
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Render a single menu item
 | |
|      *
 | |
|      * @param array $item Menu item configuration
 | |
|      */
 | |
|     private function render_menu_item($item) {
 | |
|         $has_children = !empty($item['children']);
 | |
|         $current_url = $_SERVER['REQUEST_URI'];
 | |
|         
 | |
|         // Check if this item or any of its children are active
 | |
|         $is_active = $this->is_menu_item_active($item, $current_url);
 | |
|         
 | |
|         $li_classes = array('menu-item');
 | |
|         if ($is_active) {
 | |
|             $li_classes[] = 'current-menu-item';
 | |
|         }
 | |
|         if ($has_children) {
 | |
|             $li_classes[] = 'has-children';
 | |
|         }
 | |
|         if (!empty($item['class'])) {
 | |
|             $li_classes[] = $item['class'];
 | |
|         }
 | |
|         
 | |
|         echo '<li class="' . implode(' ', $li_classes) . '">';
 | |
|         
 | |
|         // Main link
 | |
|         $link_attrs = array(
 | |
|             'href="' . esc_url($item['url']) . '"'
 | |
|         );
 | |
|         
 | |
|         if ($has_children) {
 | |
|             $link_attrs[] = 'aria-haspopup="true"';
 | |
|             $link_attrs[] = 'aria-expanded="false"';
 | |
|         }
 | |
|         
 | |
|         echo '<a ' . implode(' ', $link_attrs) . '>';
 | |
|         
 | |
|         if (!empty($item['icon'])) {
 | |
|             echo '<span class="dashicons ' . esc_attr($item['icon']) . '"></span>';
 | |
|         }
 | |
|         
 | |
|         echo '<span class="menu-title">' . esc_html($item['title']) . '</span>';
 | |
|         
 | |
|         if ($has_children) {
 | |
|             echo '<span class="menu-toggle" aria-hidden="true"></span>';
 | |
|         }
 | |
|         
 | |
|         echo '</a>';
 | |
|         
 | |
|         // Children
 | |
|         if ($has_children) {
 | |
|             echo '<ul class="sub-menu">';
 | |
|             foreach ($item['children'] as $child) {
 | |
|                 $this->render_menu_item($child);
 | |
|             }
 | |
|             echo '</ul>';
 | |
|         }
 | |
|         
 | |
|         echo '</li>';
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Check if menu item is active
 | |
|      *
 | |
|      * @param array $item Menu item
 | |
|      * @param string $current_url Current URL
 | |
|      * @return bool
 | |
|      */
 | |
|     private function is_menu_item_active($item, $current_url) {
 | |
|         // Clean URLs for comparison
 | |
|         $item_path = parse_url($item['url'], PHP_URL_PATH);
 | |
|         $current_path = parse_url($current_url, PHP_URL_PATH);
 | |
|         
 | |
|         // Check exact match
 | |
|         if ($item_path === $current_path) {
 | |
|             return true;
 | |
|         }
 | |
|         
 | |
|         // Check if current URL starts with item URL (for parent items)
 | |
|         if (!empty($item_path) && $item_path !== '/' && strpos($current_path, $item_path) === 0) {
 | |
|             return true;
 | |
|         }
 | |
|         
 | |
|         // Check children
 | |
|         if (!empty($item['children'])) {
 | |
|             foreach ($item['children'] as $child) {
 | |
|                 if ($this->is_menu_item_active($child, $current_url)) {
 | |
|                     return true;
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         
 | |
|         return false;
 | |
|     }
 | |
| }
 | |
| 
 | |
| // Initialize the class
 | |
| HVAC_Master_Menu_System::instance(); |