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 '
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 {
DashboardCertificate ReportsGenerate 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') . '
' . __('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() ) {