upskill-event-manager/includes/class-hvac-route-manager.php
bengizmo a1abbf1577 fix: Resolve duplicate content and raw shortcode display on manage event page
- Strip WordPress block editor comments (<\!-- wp:shortcode -->) from content
- Prevent duplicate header rendering when using page template vs shortcode
- Add conditional header rendering based on URL path to avoid duplication
- Header now only renders for non-hierarchical URLs where template isn't used

The manage event page was showing duplicate "Create and Manage Your HVAC Training Events"
sections and raw block editor comments because both the template and the header class
were outputting content, and block editor wrapper comments weren't being stripped.

Co-Authored-By: Ben Reed <ben@tealmaker.com>
2025-07-30 10:06:49 -03:00

403 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',
);
// 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 - run very early
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');
}
}
}