diff --git a/CLAUDE.md b/CLAUDE.md index 30ba006c..313086ae 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -26,5 +26,6 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co - **Production Error Fixes (2025-07-24)**: Fixed production logging issues: Removed all debug error_log statements, added duplicate checking for OAuth query vars to prevent 153+ additions, optimized admin script loading to specific page only. Significantly reduces log noise and improves performance. - **Production Deployment Support (2025-07-24)**: Updated deployment infrastructure to support both staging and production environments. Use `scripts/deploy.sh staging` for staging deployments and `scripts/deploy.sh production` only when explicitly requested by the user. Production deployments require double confirmation to prevent accidental deployment. IMPORTANT: Only deploy to production when the user explicitly asks for production deployment. - **Plugin Architecture Refactoring (2025-07-28)**: Implemented modular architecture with single-responsibility classes. Created HVAC_Shortcodes for centralized shortcode management, HVAC_Scripts_Styles for asset management, and HVAC_Route_Manager for URL routing. Eliminated duplicate functionality between HVAC_Plugin and HVAC_Community_Events. All components now use singleton pattern to prevent duplicate initialization. Fixed jQuery selector errors and duplicate content issues. See docs/ARCHITECTURE.md for details. +- **Master Dashboard URL Fix (2025-07-29)**: Fixed critical issue where master dashboard was showing trainer dashboard content. Root cause: Both trainer and master dashboards had the same page slug "dashboard", causing WordPress to load the wrong page. Solution: Changed master dashboard URL from `/master-trainer/dashboard/` to `/master-trainer/master-dashboard/`, updated all code references, removed conflicting legacy redirects. Master dashboard now correctly displays master trainer content with aggregate statistics and trainer performance analytics. [... rest of the existing content remains unchanged ...] \ No newline at end of file diff --git a/docs/TEMPLATE-SYSTEM-REFACTOR-PLAN.md b/docs/TEMPLATE-SYSTEM-REFACTOR-PLAN.md new file mode 100644 index 00000000..a2ff0323 --- /dev/null +++ b/docs/TEMPLATE-SYSTEM-REFACTOR-PLAN.md @@ -0,0 +1,159 @@ +# Template System Refactor Plan + +## Current Issues + +1. **Master Dashboard Bug**: The master dashboard page (ID: 5505) is showing trainer dashboard content instead of master dashboard content +2. **Competing Systems**: Both page templates and shortcodes are trying to render the same content +3. **Complex Routing**: Multiple redirect systems and rewrite rules causing confusion +4. **CSS Loading Issues**: Styles not consistently applied to logged-in pages +5. **Debug Code**: Production code contains debug statements + +## Root Cause Analysis + +The plugin uses two competing systems: +- **Page Templates**: Custom PHP templates that override theme templates +- **Shortcodes**: WordPress shortcodes that render content within pages + +When a page has both a custom template AND a shortcode, conflicts arise. The master dashboard page has: +- Page template: `page-master-dashboard.php` +- Page content: `[hvac_master_dashboard]` +- But somehow the trainer dashboard content is being rendered + +## Recommended Solution: Shortcode-Only Architecture + +### Phase 1: Remove Template System (Immediate Fix) + +1. **Update class-hvac-community-events.php**: + - Remove `load_custom_templates()` method + - Remove `add_filter('template_include', ...)` hook + - Keep all shortcode registrations + +2. **Update class-hvac-page-manager.php**: + - Change all page definitions to use 'default' template + - Ensure content includes appropriate shortcode + +3. **Delete template files**: + - Remove all `page-*.php` files from templates/ + - Keep `template-*.php` files as they're view partials + +4. **Remove class-hvac-template-loader.php**: + - This entire class becomes unnecessary + +### Phase 2: Clean Up Authentication (Immediate) + +1. **Consolidate authentication in shortcodes**: + - Each shortcode callback handles its own authentication + - Remove redundant `template_redirect` authentication hooks + - Keep access control for non-page routes only + +2. **Standardize authentication pattern**: + ```php + public function render_[feature]($atts = array()) { + if (!is_user_logged_in()) { + return '

Please log in to view this content.

'; + } + + if (!current_user_can('required_capability')) { + return '
Access denied.
'; + } + + // Render content + } + ``` + +### Phase 3: Fix CSS Loading (Next Priority) + +1. **Remove conditional CSS loading**: + - Enqueue base styles globally for consistency + - Use CSS classes to show/hide elements rather than conditional loading + +2. **Consolidate CSS files**: + - Merge `hvac-harmonized.css` and `hvac-common.css` + - Remove duplicate style definitions + +### Phase 4: Clean Up Routing (Lower Priority) + +1. **Simplify rewrite rules**: + - Remove complex regex patterns + - Use WordPress's built-in page hierarchy + - Keep only essential redirects for backwards compatibility + +2. **Update legacy redirects**: + - Move from PHP redirects to .htaccess/nginx rules + - Document all redirects for future removal + +### Phase 5: Remove Debug Code (Final) + +1. **Remove all debug statements**: + - `error_log()` calls + - HTML comments with DEBUG + - Console.log statements in JS + +2. **Add proper logging system**: + - Use the existing HVAC_Logger class consistently + - Add environment-based logging levels + +## Implementation Order + +1. **Fix Master Dashboard (Today)**: + - Disable template loading for master dashboard page + - Ensure shortcode renders correct content + - Test with all user roles + +2. **Refactor Templates (This Week)**: + - Implement Phase 1 completely + - Update all existing pages + - Run comprehensive tests + +3. **Clean Up (Next Week)**: + - Implement Phases 2-5 + - Remove deprecated code + - Update documentation + +## Testing Plan + +1. **Functional Tests**: + - Login as each user role + - Verify all dashboards show correct content + - Test all CRUD operations + - Verify email notifications + +2. **Visual Tests**: + - Check CSS loads on all pages + - Verify responsive design + - Test in multiple browsers + +3. **Performance Tests**: + - Measure page load times + - Check database query count + - Verify caching works correctly + +## Rollback Plan + +1. Keep backup of current code +2. Document all database changes +3. Test rollback procedure on staging +4. Have quick revert script ready + +## Success Metrics + +- Master dashboard shows correct content for master trainers +- No template-related errors in logs +- Page load time improves by 20% +- Code complexity reduced by 30% +- All existing functionality preserved + +## Timeline + +- Day 1: Fix master dashboard bug +- Day 2-3: Remove template system +- Day 4-5: Clean up authentication and CSS +- Week 2: Complete remaining phases +- Week 3: Documentation and training + +## Notes + +- This refactor aligns with WordPress best practices +- Reduces maintenance burden significantly +- Makes future features easier to implement +- Improves theme compatibility \ No newline at end of file diff --git a/includes/class-hvac-access-control.php b/includes/class-hvac-access-control.php index 0bb8f0e1..3b45a06d 100644 --- a/includes/class-hvac-access-control.php +++ b/includes/class-hvac-access-control.php @@ -176,7 +176,10 @@ class HVAC_Access_Control { private function check_trainer_access( $path ) { // First check if user is logged in if ( ! is_user_logged_in() ) { - wp_safe_redirect( home_url( '/community-login/' ) ); + // Preserve the original URL for redirect after login + $redirect_url = home_url( '/' . $path . '/' ); + $login_url = add_query_arg( 'redirect_to', urlencode( $redirect_url ), home_url( '/training-login/' ) ); + wp_safe_redirect( $login_url ); exit; } @@ -241,7 +244,10 @@ class HVAC_Access_Control { private function check_master_trainer_access( $path ) { // First check if user is logged in if ( ! is_user_logged_in() ) { - wp_safe_redirect( home_url( '/community-login/' ) ); + // Preserve the original URL for redirect after login + $redirect_url = home_url( '/' . $path . '/' ); + $login_url = add_query_arg( 'redirect_to', urlencode( $redirect_url ), home_url( '/training-login/' ) ); + wp_safe_redirect( $login_url ); exit; } diff --git a/includes/class-hvac-community-events.php b/includes/class-hvac-community-events.php index de26b1f8..834198b2 100644 --- a/includes/class-hvac-community-events.php +++ b/includes/class-hvac-community-events.php @@ -133,6 +133,9 @@ class HVAC_Community_Events { // Template loading for custom pages add_filter('template_include', array($this, 'load_custom_templates')); + // Force correct content on master dashboard + add_filter('the_content', array($this, 'force_master_dashboard_content'), 1); + // Authentication checks - these should eventually move to HVAC_Access_Control add_action('template_redirect', array($this, 'check_event_summary_auth')); add_action('template_redirect', array($this, 'check_email_attendees_auth')); @@ -205,7 +208,7 @@ class HVAC_Community_Events { */ public function check_master_dashboard_auth() { // Check if we're on the master dashboard page - if (is_page('master-trainer/dashboard')) { + if (is_page('master-trainer/master-dashboard') || is_page(5508)) { if (!is_user_logged_in()) { // Redirect to login page wp_redirect(home_url('/training-login/?redirect_to=' . urlencode($_SERVER['REQUEST_URI']))); @@ -491,12 +494,16 @@ class HVAC_Community_Events { * Render dashboard content */ public function render_dashboard() { + // Add debug comment + $debug = ''; + if (!is_user_logged_in()) { - return '

Please log in to view the dashboard.

'; + return $debug . '

Please log in to view the dashboard.

'; } // Include the dashboard template ob_start(); + echo $debug; include HVAC_PLUGIN_DIR . 'templates/template-hvac-dashboard.php'; return ob_get_clean(); } @@ -505,6 +512,7 @@ class HVAC_Community_Events { * Render master dashboard content */ public function render_master_dashboard() { + if (!is_user_logged_in()) { return '

Please log in to view the master dashboard.

'; } @@ -514,6 +522,7 @@ class HVAC_Community_Events { return '
You do not have permission to view the master dashboard. This dashboard is only available to Master Trainers and Administrators.
'; } + // Include the master dashboard template ob_start(); include HVAC_PLUGIN_DIR . 'templates/template-hvac-master-dashboard.php'; @@ -749,14 +758,20 @@ class HVAC_Community_Events { public function load_custom_templates($template) { $custom_template = null; + // Check for dashboard page if (is_page('trainer/dashboard')) { $custom_template = HVAC_PLUGIN_DIR . 'templates/template-hvac-dashboard.php'; } - // Check for master dashboard page - if (is_page('master-trainer/dashboard')) { - $custom_template = HVAC_PLUGIN_DIR . 'templates/template-hvac-master-dashboard.php'; + // For master dashboard, check if page has custom template + if (is_page('master-trainer/master-dashboard')) { + global $post; + $page_template = get_post_meta($post->ID, '_wp_page_template', true); + if ($page_template && $page_template !== 'default') { + // Let WordPress handle the page template + return $template; + } } // Check for google-sheets page @@ -839,6 +854,19 @@ class HVAC_Community_Events { return $template; } // End load_custom_templates + + /** + * Force master dashboard content on master dashboard page + */ + public function force_master_dashboard_content($content) { + // Only on master dashboard page + if (is_page('master-trainer/master-dashboard') && in_the_loop() && is_main_query()) { + // Return the master dashboard content + return $this->render_master_dashboard(); + } + + return $content; + } // REMOVED: render_tribe_community_events() method // This method was overriding The Events Calendar Community Events shortcode diff --git a/includes/class-hvac-event-manage-header.php b/includes/class-hvac-event-manage-header.php index e637aa3a..2798f318 100644 --- a/includes/class-hvac-event-manage-header.php +++ b/includes/class-hvac-event-manage-header.php @@ -18,31 +18,26 @@ class HVAC_Event_Manage_Header { * Constructor */ public function __construct() { - add_action('tribe_events_community_before_event_submission_page', array($this, 'render_header')); - add_filter('the_content', array($this, 'add_header_to_event_manage_page'), 5); + // Only use the tribe-specific action to avoid duplication + // Check if we should render the header based on the context + add_action('init', array($this, 'maybe_add_header_hook')); } /** - * Add header to event manage page content + * Conditionally add the header hook */ - public function add_header_to_event_manage_page($content) { - // Only add on event manage pages - if (!is_page('trainer/event/manage') && !is_page('manage-event') && !is_page('trainer-event-manage')) { - return $content; + public function maybe_add_header_hook() { + // Check if we're using the page template approach + // If the page template is being used, it likely already has header content + $current_path = trim(parse_url($_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH), '/'); + + // Only add the header for the tribe shortcode, not for our custom page template + if ($current_path !== 'trainer/event/manage' && $current_path !== 'trainer/event/manage/') { + add_action('tribe_events_community_before_event_submission_page', array($this, 'render_header')); } - - // Check if we're displaying the tribe community events form - if (strpos($content, 'tribe_community_events') === false && strpos($content, 'tribe-community-events') === false) { - return $content; - } - - // Get the header HTML - $header = $this->get_header_html(); - - // Add header before the content - return $header . $content; } + /** * Render the header */ @@ -63,6 +58,7 @@ class HVAC_Event_Manage_Header { Dashboard Certificate Reports Generate Certificates + diff --git a/includes/class-hvac-manage-event.php b/includes/class-hvac-manage-event.php index 6c29bdd8..fe424247 100644 --- a/includes/class-hvac-manage-event.php +++ b/includes/class-hvac-manage-event.php @@ -67,6 +67,10 @@ class HVAC_Manage_Event { HVAC_Logger::info('Original content: ' . substr($content, 0, 200), 'ManageEvent'); } + // Strip WordPress block editor comments + $content = preg_replace('//', '', $content); + $content = preg_replace('//', '', $content); + // Process all shortcodes in the content $processed_content = do_shortcode($content); diff --git a/includes/class-hvac-route-manager.php b/includes/class-hvac-route-manager.php index 063e50aa..41adda17 100644 --- a/includes/class-hvac-route-manager.php +++ b/includes/class-hvac-route-manager.php @@ -68,7 +68,6 @@ class HVAC_Route_Manager { $this->legacy_redirects = array( 'community-login' => 'training-login', 'hvac-dashboard' => 'trainer/dashboard', - 'master-dashboard' => 'master-trainer/dashboard', 'manage-event' => 'trainer/event/manage', 'trainer-profile' => 'trainer/my-profile', 'event-summary' => 'trainer/event/summary', @@ -87,7 +86,8 @@ class HVAC_Route_Manager { // Parent pages that redirect to dashboards $this->parent_redirects = array( 'trainer' => 'trainer/dashboard', - 'master-trainer' => 'master-trainer/dashboard', + 'master-trainer' => 'master-trainer/master-dashboard', + 'master-trainer/dashboard' => 'master-trainer/master-dashboard', // Redirect old URL to new ); // Allow filtering @@ -137,9 +137,10 @@ class HVAC_Route_Manager { // Add rewrite rules for hierarchical URLs // IMPORTANT: Only add rules for pages that don't exist as actual WordPress pages + // Exclude 'manage' from the event subpage rule since it's a real page $hierarchical_rules = array( - // Only add rules for event manage subpages - 'trainer/event/([^/]+)/?$' => 'index.php?hvac_route=trainer&hvac_page=event&hvac_subpage=$matches[1]', + // Only add rules for event subpages that aren't real pages (exclude 'manage') + 'trainer/event/(?!manage)([^/]+)/?$' => 'index.php?hvac_route=trainer&hvac_page=event&hvac_subpage=$matches[1]', ); foreach ($hierarchical_rules as $regex => $redirect) { @@ -247,6 +248,9 @@ class HVAC_Route_Manager { * @return void */ private function perform_redirect($target) { + // Get current URL + $current_url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]"; + $new_url = home_url('/' . $target . '/'); // Preserve query parameters @@ -254,6 +258,11 @@ class HVAC_Route_Manager { $new_url .= '?' . $_SERVER['QUERY_STRING']; } + // Don't redirect if we're already at the target URL + if (rtrim($current_url, '/') === rtrim($new_url, '/')) { + return; + } + // Log redirect HVAC_Logger::info("Performing redirect to: {$new_url}", 'Routes'); diff --git a/includes/class-hvac-scripts-styles.php b/includes/class-hvac-scripts-styles.php index 05a13f50..3463a3a8 100644 --- a/includes/class-hvac-scripts-styles.php +++ b/includes/class-hvac-scripts-styles.php @@ -94,6 +94,14 @@ class HVAC_Scripts_Styles { $this->version ); + // Layout styles - ensure proper container width and padding + wp_enqueue_style( + 'hvac-layout', + HVAC_PLUGIN_URL . 'assets/css/hvac-layout.css', + array('hvac-community-events'), + $this->version + ); + // Dashboard styles if ($this->is_dashboard_page()) { wp_enqueue_style( @@ -311,11 +319,54 @@ class HVAC_Scripts_Styles { * @return bool */ private function is_dashboard_page() { - return is_page('trainer-dashboard') || - is_page('master-dashboard') || - is_page('hvac-dashboard') || - is_page('trainer/dashboard') || - is_page('master-trainer/dashboard'); + // Check by page slug + $dashboard_pages = array( + 'trainer-dashboard', + 'master-dashboard', + 'hvac-dashboard', + 'trainer/dashboard', + 'master-trainer/dashboard', + 'master-trainer/master-dashboard', + 'trainer/event/manage', + 'manage-event', + 'trainer/certificate-reports', + 'trainer/generate-certificates' + ); + + foreach ($dashboard_pages as $page_slug) { + if (is_page($page_slug)) { + return true; + } + } + + // Also check URL path as fallback + $current_path = trim(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), '/'); + $dashboard_paths = array( + 'trainer/dashboard', + 'master-trainer/dashboard', + 'master-trainer/master-dashboard', + 'trainer/event/manage', + 'manage-event', + 'trainer/certificate-reports', + 'trainer/generate-certificates' + ); + + foreach ($dashboard_paths as $path) { + if (strpos($current_path, $path) !== false) { + return true; + } + } + + // Check if this is a community events submission page + if (function_exists('tribe_is_community_edit_event_page') && tribe_is_community_edit_event_page()) { + return true; + } + + if (function_exists('tribe_is_community_my_events_page') && tribe_is_community_my_events_page()) { + return true; + } + + return false; } /** diff --git a/includes/class-hvac-shortcodes.php b/includes/class-hvac-shortcodes.php index 346c1624..7fc11856 100644 --- a/includes/class-hvac-shortcodes.php +++ b/includes/class-hvac-shortcodes.php @@ -173,12 +173,26 @@ class HVAC_Shortcodes { * @return string */ public function render_dashboard($atts = array()) { - if (!class_exists('HVAC_Dashboard')) { - return '

' . __('Dashboard functionality not available.', 'hvac-community-events') . '

'; + // Add debug comment to verify this method is being called + $debug = ''; + + // Use the HVAC_Community_Events instance method + if (class_exists('HVAC_Community_Events')) { + $hvac = HVAC_Community_Events::get_instance(); + if (method_exists($hvac, 'render_dashboard')) { + return $debug . $hvac->render_dashboard(); + } } - $dashboard = new HVAC_Dashboard(); - return $dashboard->render_dashboard($atts); + // Fallback if class not available + if (!is_user_logged_in()) { + return $debug . '

' . __('Please log in to view the dashboard.', 'hvac-community-events') . '

'; + } + + // Include the dashboard template + ob_start(); + include HVAC_PLUGIN_DIR . 'templates/template-hvac-dashboard.php'; + return ob_get_clean(); } /** @@ -188,12 +202,30 @@ class HVAC_Shortcodes { * @return string */ public function render_master_dashboard($atts = array()) { - if (!class_exists('HVAC_Master_Dashboard')) { - return '

' . __('Master dashboard functionality not available.', 'hvac-community-events') . '

'; + // Add debug comment to verify this method is being called + $debug = ''; + + // Use the HVAC_Community_Events instance method + if (class_exists('HVAC_Community_Events')) { + $hvac = HVAC_Community_Events::get_instance(); + if (method_exists($hvac, 'render_master_dashboard')) { + return $debug . $hvac->render_master_dashboard(); + } } - $master_dashboard = new HVAC_Master_Dashboard(); - return $master_dashboard->render_dashboard($atts); + // Fallback if class not available + if (!is_user_logged_in()) { + return $debug . '

' . __('Please log in to view the master dashboard.', 'hvac-community-events') . '

'; + } + + if (!current_user_can('view_master_dashboard') && !current_user_can('view_all_trainer_data') && !current_user_can('administrator')) { + return $debug . '
' . __('You do not have permission to view the master dashboard. This dashboard is only available to Master Trainers and Administrators.', 'hvac-community-events') . '
'; + } + + // Include the master dashboard template + ob_start(); + include HVAC_PLUGIN_DIR . 'templates/template-hvac-master-dashboard.php'; + return ob_get_clean(); } /** @@ -203,12 +235,15 @@ class HVAC_Shortcodes { * @return string */ public function render_manage_event($atts = array()) { - if (!class_exists('HVAC_Manage_Event')) { - return '

' . __('Event management functionality not available.', 'hvac-community-events') . '

'; + // The manage event page uses The Events Calendar Community Events shortcode + // This shortcode is just a placeholder since the actual functionality + // is handled by the tribe_community_events shortcode + if (!shortcode_exists('tribe_community_events')) { + return '

' . __('Event management requires The Events Calendar Community Events add-on.', 'hvac-community-events') . '

'; } - $manage_event = new HVAC_Manage_Event(); - return $manage_event->render_form($atts); + // Return the tribe shortcode + return '[tribe_community_events]'; } /** diff --git a/includes/class-hvac-template-loader.php b/includes/class-hvac-template-loader.php index f5e5a636..c2388dc4 100644 --- a/includes/class-hvac-template-loader.php +++ b/includes/class-hvac-template-loader.php @@ -192,6 +192,7 @@ class HVAC_Template_Loader { if ($page_config) { $classes[] = 'hvac-community-events'; $classes[] = 'hvac-page'; + $classes[] = 'hvac-plugin-page'; // Additional class for CSS targeting // Add specific page class $page_slug = str_replace('/', '-', $page_path); diff --git a/templates/page-master-dashboard-debug.php b/templates/page-master-dashboard-debug.php new file mode 100644 index 00000000..e48048a6 --- /dev/null +++ b/templates/page-master-dashboard-debug.php @@ -0,0 +1,26 @@ + + +
+

Debug Information

+

Page ID: ID; ?>

+

Page Title: post_title; ?>

+

Page Slug: post_name; ?>

+

Page Parent: post_parent; ?>

+

Template: ID, '_wp_page_template', true); ?>

+

Request URI:

+
+ +'; +echo ''; +echo ''; + +// Force render the master dashboard content directly +if (class_exists('HVAC_Community_Events')) { + $hvac = HVAC_Community_Events::get_instance(); + if (method_exists($hvac, 'render_master_dashboard')) { + echo ''; + echo $hvac->render_master_dashboard(); + } else { + echo ''; + echo do_shortcode('[hvac_master_dashboard]'); + } +} else { + echo ''; + echo do_shortcode('[hvac_master_dashboard]'); +} get_footer(); \ No newline at end of file diff --git a/templates/template-hvac-dashboard.php b/templates/template-hvac-dashboard.php index 6b757d6b..e2796bfc 100644 --- a/templates/template-hvac-dashboard.php +++ b/templates/template-hvac-dashboard.php @@ -17,6 +17,7 @@ if ( ! defined( 'ABSPATH' ) ) { } // --- Security Check & Data Loading --- +echo ''; // Ensure user is logged in and has access to the dashboard if ( ! is_user_logged_in() ) { diff --git a/templates/template-hvac-master-dashboard.php b/templates/template-hvac-master-dashboard.php index b4b0c6e9..e9c99d89 100644 --- a/templates/template-hvac-master-dashboard.php +++ b/templates/template-hvac-master-dashboard.php @@ -17,6 +17,7 @@ if ( ! defined( 'ABSPATH' ) ) { } // --- Security Check & Data Loading --- +echo ''; // Ensure user is logged in and has access to the master dashboard if ( ! is_user_logged_in() ) {