Fixes multiple authentication system conflicts causing redirect loops that prevented all trainer and master trainer pages from loading. Root cause: Three authentication systems competing on template_redirect: - HVAC_Route_Manager (priority 1) - HVAC_Plugin (priority 5) - HVAC_Access_Control (priority 10) Solution: Temporarily disable conflicting systems, keep HVAC_Access_Control as primary authentication handler. Verified working: - /trainer/dashboard/, /trainer/venue/list/, /trainer/venue/manage/ - /master-trainer/dashboard/, /master-trainer/announcements/, /master-trainer/trainers/ Phase 1 Native Event System now fully operational in production. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
404 lines
No EOL
12 KiB
PHP
404 lines
No EOL
12 KiB
PHP
<?php
|
|
/**
|
|
* HVAC Route Manager
|
|
*
|
|
* Centralized management of URL routing, redirects, and rewrite rules
|
|
*
|
|
* @package HVAC_Community_Events
|
|
* @since 2.0.0
|
|
*/
|
|
|
|
if (!defined('ABSPATH')) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* HVAC_Route_Manager class
|
|
*/
|
|
class HVAC_Route_Manager {
|
|
|
|
/**
|
|
* Instance
|
|
*
|
|
* @var HVAC_Route_Manager
|
|
*/
|
|
private static $instance = null;
|
|
|
|
/**
|
|
* Legacy redirect mappings
|
|
*
|
|
* @var array
|
|
*/
|
|
private $legacy_redirects = array();
|
|
|
|
/**
|
|
* Parent page redirects
|
|
*
|
|
* @var array
|
|
*/
|
|
private $parent_redirects = array();
|
|
|
|
/**
|
|
* Get instance
|
|
*
|
|
* @return HVAC_Route_Manager
|
|
*/
|
|
public static function instance() {
|
|
if (null === self::$instance) {
|
|
self::$instance = new self();
|
|
}
|
|
return self::$instance;
|
|
}
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
private function __construct() {
|
|
$this->define_redirects();
|
|
$this->init_hooks();
|
|
}
|
|
|
|
/**
|
|
* Define redirect mappings
|
|
*
|
|
* @return void
|
|
*/
|
|
private function define_redirects() {
|
|
// Legacy URL to new URL mappings
|
|
$this->legacy_redirects = array(
|
|
'community-login' => 'training-login',
|
|
'hvac-dashboard' => 'trainer/dashboard',
|
|
'manage-event' => 'trainer/event/manage',
|
|
'trainer-profile' => 'trainer/my-profile',
|
|
'event-summary' => 'trainer/event/summary',
|
|
'email-attendees' => 'trainer/email-attendees',
|
|
'certificate-reports' => 'trainer/certificate-reports',
|
|
'generate-certificates' => 'trainer/generate-certificates',
|
|
'certificate-fix' => 'master-trainer/certificate-fix',
|
|
'hvac-documentation' => 'trainer/documentation',
|
|
'attendee-profile' => 'trainer/attendee-profile',
|
|
'google-sheets' => 'master-trainer/google-sheets',
|
|
'communication-templates' => 'trainer/communication-templates',
|
|
'communication-schedules' => 'trainer/communication-schedules',
|
|
'trainer-registration' => 'trainer/registration',
|
|
'find-trainer' => 'find-a-trainer', // Fix E2E testing URL mismatch
|
|
);
|
|
|
|
// Parent pages that redirect to dashboards
|
|
$this->parent_redirects = array(
|
|
'trainer' => 'trainer/dashboard',
|
|
'master-trainer' => 'master-trainer/master-dashboard',
|
|
'master-trainer/dashboard' => 'master-trainer/master-dashboard', // Redirect old URL to new
|
|
);
|
|
|
|
// Allow filtering
|
|
$this->legacy_redirects = apply_filters('hvac_legacy_redirects', $this->legacy_redirects);
|
|
$this->parent_redirects = apply_filters('hvac_parent_redirects', $this->parent_redirects);
|
|
}
|
|
|
|
/**
|
|
* Initialize hooks
|
|
*
|
|
* @return void
|
|
*/
|
|
private function init_hooks() {
|
|
// Register rewrite rules
|
|
add_action('init', array($this, 'register_rewrite_rules'), 5);
|
|
|
|
// Handle redirects - TEMPORARILY DISABLED due to conflict with HVAC_Access_Control
|
|
// add_action('template_redirect', array($this, 'handle_redirects'), 1);
|
|
|
|
// Intercept page queries for legacy URLs
|
|
add_action('pre_get_posts', array($this, 'intercept_legacy_page_queries'), 1);
|
|
|
|
// Register query vars
|
|
add_filter('query_vars', array($this, 'register_query_vars'));
|
|
|
|
// Handle legacy redirect requests
|
|
add_action('parse_request', array($this, 'handle_legacy_redirect_request'));
|
|
|
|
// Flush rewrite rules on activation
|
|
add_action('hvac_plugin_activated', array($this, 'flush_rewrite_rules'));
|
|
}
|
|
|
|
/**
|
|
* Register rewrite rules
|
|
*
|
|
* @return void
|
|
*/
|
|
public function register_rewrite_rules() {
|
|
// Add rewrite rules for legacy URLs
|
|
foreach ($this->legacy_redirects as $legacy => $new) {
|
|
add_rewrite_rule(
|
|
'^' . $legacy . '/?$',
|
|
'index.php?hvac_legacy_redirect=' . $legacy,
|
|
'top'
|
|
);
|
|
}
|
|
|
|
// 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 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) {
|
|
add_rewrite_rule($regex, $redirect, 'top');
|
|
}
|
|
|
|
// Log registration
|
|
HVAC_Logger::info('Registered ' . count($this->legacy_redirects) . ' legacy redirects and ' . count($hierarchical_rules) . ' hierarchical rules', 'Routes');
|
|
}
|
|
|
|
/**
|
|
* Register query vars
|
|
*
|
|
* @param array $vars Query vars
|
|
* @return array
|
|
*/
|
|
public function register_query_vars($vars) {
|
|
$vars[] = 'hvac_legacy_redirect';
|
|
$vars[] = 'hvac_route';
|
|
$vars[] = 'hvac_page';
|
|
$vars[] = 'hvac_subpage';
|
|
|
|
return $vars;
|
|
}
|
|
|
|
/**
|
|
* Handle legacy redirect requests
|
|
*
|
|
* @param WP $wp WordPress environment instance
|
|
* @return void
|
|
*/
|
|
public function handle_legacy_redirect_request($wp) {
|
|
if (!isset($wp->query_vars['hvac_legacy_redirect'])) {
|
|
return;
|
|
}
|
|
|
|
$legacy_slug = $wp->query_vars['hvac_legacy_redirect'];
|
|
|
|
if (isset($this->legacy_redirects[$legacy_slug])) {
|
|
$new_url = home_url('/' . $this->legacy_redirects[$legacy_slug] . '/');
|
|
|
|
// Preserve query parameters
|
|
if (!empty($_SERVER['QUERY_STRING'])) {
|
|
$new_url .= '?' . $_SERVER['QUERY_STRING'];
|
|
}
|
|
|
|
// Log redirect
|
|
HVAC_Logger::info("Redirecting legacy URL: {$legacy_slug} to {$new_url}", 'Routes');
|
|
|
|
wp_redirect($new_url, 301);
|
|
exit;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Handle redirects
|
|
*
|
|
* @return void
|
|
*/
|
|
public function handle_redirects() {
|
|
// Get current URL path
|
|
$current_path = trim(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), '/');
|
|
|
|
// Handle legacy redirects
|
|
if (isset($this->legacy_redirects[$current_path])) {
|
|
$this->perform_redirect($this->legacy_redirects[$current_path]);
|
|
}
|
|
|
|
// Handle parent page redirects
|
|
if (isset($this->parent_redirects[$current_path])) {
|
|
$this->perform_redirect($this->parent_redirects[$current_path]);
|
|
}
|
|
|
|
// Also check if this is a 404 that should redirect
|
|
if (is_404()) {
|
|
// Check without trailing slash
|
|
$path_no_slash = rtrim($current_path, '/');
|
|
if (isset($this->legacy_redirects[$path_no_slash])) {
|
|
$this->perform_redirect($this->legacy_redirects[$path_no_slash]);
|
|
}
|
|
|
|
// Check with just the last segment (for pages that might exist but shouldn't)
|
|
$segments = explode('/', $current_path);
|
|
$last_segment = end($segments);
|
|
if ($last_segment && isset($this->legacy_redirects[$last_segment])) {
|
|
$this->perform_redirect($this->legacy_redirects[$last_segment]);
|
|
}
|
|
}
|
|
|
|
// Also check if this is a page that exists with a legacy slug
|
|
global $post;
|
|
if (is_page() && $post) {
|
|
$current_slug = $post->post_name;
|
|
|
|
if (isset($this->legacy_redirects[$current_slug])) {
|
|
$this->perform_redirect($this->legacy_redirects[$current_slug]);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Perform redirect
|
|
*
|
|
* @param string $target Target path
|
|
* @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
|
|
if (!empty($_SERVER['QUERY_STRING'])) {
|
|
$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');
|
|
|
|
wp_redirect($new_url, 301);
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Get legacy redirects
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_legacy_redirects() {
|
|
return $this->legacy_redirects;
|
|
}
|
|
|
|
/**
|
|
* Get parent redirects
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_parent_redirects() {
|
|
return $this->parent_redirects;
|
|
}
|
|
|
|
/**
|
|
* Add custom redirect
|
|
*
|
|
* @param string $from From path
|
|
* @param string $to To path
|
|
* @param string $type Type of redirect (legacy or parent)
|
|
* @return void
|
|
*/
|
|
public function add_redirect($from, $to, $type = 'legacy') {
|
|
if ($type === 'legacy') {
|
|
$this->legacy_redirects[$from] = $to;
|
|
} elseif ($type === 'parent') {
|
|
$this->parent_redirects[$from] = $to;
|
|
}
|
|
|
|
// Re-register rules if already initialized
|
|
if (did_action('init')) {
|
|
$this->register_rewrite_rules();
|
|
flush_rewrite_rules();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove redirect
|
|
*
|
|
* @param string $from From path
|
|
* @param string $type Type of redirect (legacy or parent)
|
|
* @return void
|
|
*/
|
|
public function remove_redirect($from, $type = 'legacy') {
|
|
if ($type === 'legacy' && isset($this->legacy_redirects[$from])) {
|
|
unset($this->legacy_redirects[$from]);
|
|
} elseif ($type === 'parent' && isset($this->parent_redirects[$from])) {
|
|
unset($this->parent_redirects[$from]);
|
|
}
|
|
|
|
// Re-register rules if already initialized
|
|
if (did_action('init')) {
|
|
$this->register_rewrite_rules();
|
|
flush_rewrite_rules();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Flush rewrite rules
|
|
*
|
|
* @return void
|
|
*/
|
|
public function flush_rewrite_rules() {
|
|
flush_rewrite_rules();
|
|
HVAC_Logger::info('Flushed rewrite rules', 'Routes');
|
|
}
|
|
|
|
/**
|
|
* Check if URL needs redirect
|
|
*
|
|
* @param string $url URL to check
|
|
* @return string|false Redirect target or false
|
|
*/
|
|
public function needs_redirect($url) {
|
|
$path = trim(parse_url($url, PHP_URL_PATH), '/');
|
|
|
|
if (isset($this->legacy_redirects[$path])) {
|
|
return $this->legacy_redirects[$path];
|
|
}
|
|
|
|
if (isset($this->parent_redirects[$path])) {
|
|
return $this->parent_redirects[$path];
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Intercept page queries for legacy URLs
|
|
*
|
|
* This prevents WordPress from finding pages with legacy slugs
|
|
* and allows our redirects to work properly
|
|
*
|
|
* @param WP_Query $query The WordPress query object
|
|
* @return void
|
|
*/
|
|
public function intercept_legacy_page_queries($query) {
|
|
// Only run on the main query on the frontend
|
|
if (!$query->is_main_query() || is_admin()) {
|
|
return;
|
|
}
|
|
|
|
// Check if this is a page query
|
|
if (!$query->is_page()) {
|
|
return;
|
|
}
|
|
|
|
// Get the page name being queried
|
|
$pagename = $query->get('pagename');
|
|
if (empty($pagename)) {
|
|
return;
|
|
}
|
|
|
|
// Check if this is a legacy URL that should redirect
|
|
if (isset($this->legacy_redirects[$pagename])) {
|
|
// Prevent WordPress from finding this page
|
|
$query->set('page_id', -1);
|
|
$query->set('pagename', '');
|
|
|
|
// Force a 404 which will trigger our template_redirect
|
|
$query->set_404();
|
|
|
|
// Log for debugging
|
|
HVAC_Logger::info("Intercepted legacy page query: {$pagename}", 'Routes');
|
|
}
|
|
}
|
|
} |