Some checks failed
Security Monitoring & Compliance / Static Code Security Analysis (push) Has been cancelled
Security Monitoring & Compliance / Security Compliance Validation (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Security Analysis (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Code Quality & Standards (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Unit Tests (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Integration Tests (push) Has been cancelled
Security Monitoring & Compliance / Dependency Vulnerability Scan (push) Has been cancelled
Security Monitoring & Compliance / Secrets & Credential Scan (push) Has been cancelled
Security Monitoring & Compliance / WordPress Security Analysis (push) Has been cancelled
Security Monitoring & Compliance / Security Summary Report (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Deploy to Staging (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Deploy to Production (push) Has been cancelled
HVAC Plugin CI/CD Pipeline / Notification (push) Has been cancelled
Security Monitoring & Compliance / Security Team Notification (push) Has been cancelled
Major modernization of HVAC plugin for PHP 8+ with full backward compatibility: CORE MODERNIZATION: - Implement strict type declarations throughout codebase - Modernize main plugin class with PHP 8+ features - Convert array syntax to modern PHP format - Add constructor property promotion where applicable - Enhance security helpers with modern PHP patterns COMPATIBILITY FIXES: - Fix PHP 8.1+ enum compatibility (convert to class constants) - Fix union type compatibility (true|WP_Error → bool|WP_Error) - Remove mixed type declarations for PHP 8.0 compatibility - Add default arms to match expressions preventing UnhandledMatchError - Fix method naming inconsistency (ensureRegistrationAccess callback) - Add null coalescing in TEC integration for strict type compliance DEPLOYMENT STATUS: ✅ Successfully deployed and tested on staging ✅ Site functional at https://upskill-staging.measurequick.com ✅ Expert code review completed with GPT-5 validation ✅ MCP Playwright testing confirms functionality Ready for production deployment when requested. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
363 lines
No EOL
11 KiB
PHP
363 lines
No EOL
11 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* HVAC Community Events - Access Control
|
|
*
|
|
* Handles page access restrictions based on trainer status
|
|
*
|
|
* @package HVAC_Community_Events
|
|
* @since 1.0.0
|
|
*/
|
|
|
|
// Exit if accessed directly
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Class HVAC_Access_Control
|
|
*
|
|
* Manages access control for trainer pages based on account status
|
|
*/
|
|
class HVAC_Access_Control {
|
|
|
|
/**
|
|
* Pages that require authentication but no specific status
|
|
*/
|
|
private static $public_pages = [
|
|
'trainer/registration',
|
|
'registration-pending',
|
|
'community-login',
|
|
'training-login',
|
|
'trainer-account-pending',
|
|
'trainer-account-disabled',
|
|
];
|
|
|
|
/**
|
|
* Pages that require trainer to be active or inactive
|
|
*/
|
|
private static $trainer_pages = [
|
|
'trainer/dashboard',
|
|
'trainer/event/manage',
|
|
'trainer/event/edit',
|
|
'trainer/generate-certificates',
|
|
'trainer/certificate-reports',
|
|
'trainer/event/summary',
|
|
'trainer/email-attendees',
|
|
'trainer/communication-templates',
|
|
'edit-profile',
|
|
];
|
|
|
|
/**
|
|
* Pages that require master trainer role
|
|
*/
|
|
private static $master_trainer_pages = [
|
|
'master-trainer/master-dashboard',
|
|
'master-trainer/certificate-fix',
|
|
'master-trainer/google-sheets',
|
|
];
|
|
|
|
/**
|
|
* Constructor
|
|
*/
|
|
public function __construct() {
|
|
// Hook into template_redirect for access control
|
|
add_action( 'template_redirect', [ $this, 'check_page_access' ], 10 );
|
|
}
|
|
|
|
/**
|
|
* Check page access based on user status
|
|
*/
|
|
public function check_page_access() {
|
|
// Get current page path
|
|
$current_path = trim( parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH ), '/' );
|
|
|
|
// Check if this is a legacy URL that will be redirected
|
|
if ( $this->is_legacy_url( $current_path ) ) {
|
|
// Allow the redirect to happen first
|
|
return;
|
|
}
|
|
|
|
// Check if this is a public page
|
|
if ( $this->is_public_page( $current_path ) ) {
|
|
return;
|
|
}
|
|
|
|
// Check if this is a trainer page
|
|
if ( $this->is_trainer_page( $current_path ) ) {
|
|
$this->check_trainer_access( $current_path );
|
|
}
|
|
|
|
// Check if this is a master trainer page
|
|
if ( $this->is_master_trainer_page( $current_path ) ) {
|
|
$this->check_master_trainer_access( $current_path );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if current URL is a legacy URL that should be redirected
|
|
*
|
|
* @param string $path Current page path
|
|
* @return bool
|
|
*/
|
|
private function is_legacy_url( $path ) {
|
|
// Get the route manager instance
|
|
if ( ! class_exists( 'HVAC_Route_Manager' ) ) {
|
|
return false;
|
|
}
|
|
|
|
$route_manager = HVAC_Route_Manager::instance();
|
|
|
|
// Check if this path needs a redirect
|
|
return $route_manager->needs_redirect( $path ) !== false;
|
|
}
|
|
|
|
/**
|
|
* Check if current page is public
|
|
*
|
|
* @param string $path Current page path
|
|
* @return bool
|
|
*/
|
|
private function is_public_page( $path ) {
|
|
foreach ( self::$public_pages as $public_page ) {
|
|
if ( $path === $public_page || strpos( $path, $public_page ) === 0 ) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if current page is a trainer page
|
|
*
|
|
* @param string $path Current page path
|
|
* @return bool
|
|
*/
|
|
private function is_trainer_page( $path ) {
|
|
foreach ( self::$trainer_pages as $trainer_page ) {
|
|
if ( $path === $trainer_page || strpos( $path, $trainer_page ) === 0 ) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Also check for pages that start with 'trainer/'
|
|
if ( strpos( $path, 'trainer/' ) === 0 ) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if current page is a master trainer page
|
|
*
|
|
* @param string $path Current page path
|
|
* @return bool
|
|
*/
|
|
private function is_master_trainer_page( $path ) {
|
|
foreach ( self::$master_trainer_pages as $master_page ) {
|
|
if ( $path === $master_page || strpos( $path, $master_page ) === 0 ) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Also check for pages that start with 'master-trainer/'
|
|
if ( strpos( $path, 'master-trainer/' ) === 0 ) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check trainer access to protected pages
|
|
*
|
|
* @param string $path Current page path
|
|
*/
|
|
private function check_trainer_access( $path ) {
|
|
// First check if user is logged in
|
|
if ( ! is_user_logged_in() ) {
|
|
// Preserve the original URL for redirect after login
|
|
$redirect_url = home_url( '/' . $path . '/' );
|
|
$login_url = add_query_arg( 'redirect_to', $redirect_url, home_url( '/training-login/' ) );
|
|
wp_safe_redirect( $login_url );
|
|
exit;
|
|
}
|
|
|
|
$user_id = get_current_user_id();
|
|
$user = wp_get_current_user();
|
|
|
|
// Allow administrators full access
|
|
if ( current_user_can( 'manage_options' ) ) {
|
|
return;
|
|
}
|
|
|
|
// Check if user has trainer role
|
|
if ( ! in_array( 'hvac_trainer', $user->roles ) && ! in_array( 'hvac_master_trainer', $user->roles ) ) {
|
|
// Not a trainer, show access denied
|
|
$this->show_access_denied();
|
|
return;
|
|
}
|
|
|
|
// Get trainer status
|
|
if ( ! class_exists( 'HVAC_Trainer_Status' ) ) {
|
|
require_once HVAC_PLUGIN_DIR . 'includes/class-hvac-trainer-status.php';
|
|
}
|
|
|
|
$status = HVAC_Trainer_Status::get_trainer_status( $user_id );
|
|
|
|
// Handle based on status
|
|
switch ( $status ) {
|
|
case HVAC_Trainer_Status::STATUS_PENDING:
|
|
// Redirect to pending page
|
|
if ( $path !== 'trainer-account-pending' && strpos( $path, 'trainer-account-pending' ) !== 0 ) {
|
|
wp_safe_redirect( home_url( '/trainer-account-pending/' ) );
|
|
exit;
|
|
}
|
|
break;
|
|
|
|
case HVAC_Trainer_Status::STATUS_DISABLED:
|
|
// Redirect to disabled page
|
|
if ( $path !== 'trainer-account-disabled' && strpos( $path, 'trainer-account-disabled' ) !== 0 ) {
|
|
wp_safe_redirect( home_url( '/trainer-account-disabled/' ) );
|
|
exit;
|
|
}
|
|
break;
|
|
|
|
case HVAC_Trainer_Status::STATUS_APPROVED:
|
|
case HVAC_Trainer_Status::STATUS_ACTIVE:
|
|
case HVAC_Trainer_Status::STATUS_INACTIVE:
|
|
// Allow access
|
|
break;
|
|
|
|
default:
|
|
// Unknown status, treat as pending
|
|
wp_safe_redirect( home_url( '/trainer-account-pending/' ) );
|
|
exit;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check master trainer access to protected pages
|
|
*
|
|
* @param string $path Current page path
|
|
*/
|
|
private function check_master_trainer_access( $path ) {
|
|
// First check if user is logged in
|
|
if ( ! is_user_logged_in() ) {
|
|
// Preserve the original URL for redirect after login
|
|
$redirect_url = home_url( '/' . $path . '/' );
|
|
$login_url = add_query_arg( 'redirect_to', $redirect_url, home_url( '/training-login/' ) );
|
|
wp_safe_redirect( $login_url );
|
|
exit;
|
|
}
|
|
|
|
$user = wp_get_current_user();
|
|
|
|
// Allow administrators full access
|
|
if ( current_user_can( 'manage_options' ) ) {
|
|
return;
|
|
}
|
|
|
|
// Check if user has master trainer role
|
|
if ( ! in_array( 'hvac_master_trainer', $user->roles ) ) {
|
|
// Not a master trainer, show access denied
|
|
$this->show_access_denied();
|
|
return;
|
|
}
|
|
|
|
// Master trainers have access to all their pages
|
|
// No need to check status for master trainers
|
|
}
|
|
|
|
/**
|
|
* Show access denied page
|
|
*/
|
|
private function show_access_denied() {
|
|
get_header();
|
|
?>
|
|
<style>
|
|
.hvac-access-denied {
|
|
max-width: 600px;
|
|
margin: 60px auto;
|
|
padding: 40px;
|
|
text-align: center;
|
|
background: #fff;
|
|
border-radius: 8px;
|
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|
}
|
|
.hvac-access-denied h1 {
|
|
color: #d63638;
|
|
margin-bottom: 20px;
|
|
}
|
|
.hvac-access-denied p {
|
|
margin-bottom: 15px;
|
|
color: #666;
|
|
line-height: 1.6;
|
|
}
|
|
.hvac-access-denied .button {
|
|
background: #0073aa;
|
|
color: white;
|
|
padding: 12px 24px;
|
|
text-decoration: none;
|
|
border-radius: 4px;
|
|
display: inline-block;
|
|
margin-top: 20px;
|
|
}
|
|
.hvac-access-denied .button:hover {
|
|
background: #005a87;
|
|
color: white;
|
|
}
|
|
</style>
|
|
<div class="content-area primary ast-container">
|
|
<main class="site-main">
|
|
<div class="hvac-access-denied">
|
|
<h1><?php _e( 'Access Denied', 'hvac-community-events' ); ?></h1>
|
|
<p><?php _e( 'You do not have permission to access this page.', 'hvac-community-events' ); ?></p>
|
|
<p><?php _e( 'If you believe this is an error, please contact an administrator.', 'hvac-community-events' ); ?></p>
|
|
<a href="<?php echo esc_url( home_url() ); ?>" class="button"><?php _e( 'Return to Home', 'hvac-community-events' ); ?></a>
|
|
</div>
|
|
</main>
|
|
</div>
|
|
<?php
|
|
get_footer();
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Add custom pages that require specific access
|
|
*
|
|
* @param string $page Page path
|
|
* @param string $type 'public' or 'trainer'
|
|
*/
|
|
public static function add_custom_page( $page, $type = 'trainer' ) {
|
|
if ( $type === 'public' ) {
|
|
self::$public_pages[] = $page;
|
|
} else {
|
|
self::$trainer_pages[] = $page;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Remove a page from access control
|
|
*
|
|
* @param string $page Page path
|
|
* @param string $type 'public' or 'trainer'
|
|
*/
|
|
public static function remove_custom_page( $page, $type = 'trainer' ) {
|
|
if ( $type === 'public' ) {
|
|
$key = array_search( $page, self::$public_pages );
|
|
if ( $key !== false ) {
|
|
unset( self::$public_pages[$key] );
|
|
}
|
|
} else {
|
|
$key = array_search( $page, self::$trainer_pages );
|
|
if ( $key !== false ) {
|
|
unset( self::$trainer_pages[$key] );
|
|
}
|
|
}
|
|
}
|
|
}
|