- Implement singleton pattern for HVAC_Enhanced_Settings to prevent duplicate initialization - Fix jQuery selector error by checking for valid hash selectors before using $(href) - Add default email templates with professional copy for trainer notifications - Update plugin version to 1.0.1 for cache busting - Remove duplicate Enhanced Settings initialization from HVAC_Community_Events - Add force cache refresh suffix to admin scripts This resolves the duplicate content issue on email templates page and fixes JavaScript errors in the admin interface. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
		
			
				
	
	
		
			423 lines
		
	
	
		
			No EOL
		
	
	
		
			17 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			423 lines
		
	
	
		
			No EOL
		
	
	
		
			17 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| /**
 | |
|  * HVAC Community Events - Approval Workflow
 | |
|  *
 | |
|  * Handles trainer approval workflow and email notifications
 | |
|  *
 | |
|  * @package HVAC_Community_Events
 | |
|  * @since 1.0.0
 | |
|  */
 | |
| 
 | |
| // Exit if accessed directly
 | |
| if ( ! defined( 'ABSPATH' ) ) {
 | |
|     exit;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Class HVAC_Approval_Workflow
 | |
|  *
 | |
|  * Manages the trainer approval process including email notifications
 | |
|  */
 | |
| class HVAC_Approval_Workflow {
 | |
|     
 | |
|     /**
 | |
|      * Constructor
 | |
|      */
 | |
|     public function __construct() {
 | |
|         // Hook into trainer status changes
 | |
|         add_action( 'hvac_trainer_status_changed', array( $this, 'handle_status_change' ), 10, 3 );
 | |
|         
 | |
|         // Add query variable for approval token
 | |
|         add_filter( 'query_vars', array( $this, 'add_query_vars' ) );
 | |
|         
 | |
|         // Handle approval URL visits
 | |
|         add_action( 'template_redirect', array( $this, 'handle_approval_request' ), 5 );
 | |
|         
 | |
|         // Add AJAX handlers for bulk updates
 | |
|         add_action( 'wp_ajax_hvac_bulk_update_trainer_status', array( $this, 'ajax_bulk_update_status' ) );
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Add query variables for approval
 | |
|      */
 | |
|     public function add_query_vars( $vars ) {
 | |
|         $vars[] = 'hvac_approve_trainer';
 | |
|         $vars[] = 'hvac_approval_token';
 | |
|         return $vars;
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Handle trainer status changes
 | |
|      *
 | |
|      * @param int $user_id User ID
 | |
|      * @param string $new_status New status
 | |
|      * @param string $old_status Old status
 | |
|      */
 | |
|     public function handle_status_change( $user_id, $new_status, $old_status ) {
 | |
|         // Send appropriate notifications based on status change
 | |
|         if ( $new_status === HVAC_Trainer_Status::STATUS_APPROVED && $old_status === HVAC_Trainer_Status::STATUS_PENDING ) {
 | |
|             $this->send_approval_notification( $user_id );
 | |
|         } elseif ( $new_status === HVAC_Trainer_Status::STATUS_DISABLED ) {
 | |
|             $this->send_disabled_notification( $user_id );
 | |
|         }
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Send new registration notification to admins
 | |
|      *
 | |
|      * @param int $user_id User ID
 | |
|      * @param array $registration_data Registration form data
 | |
|      */
 | |
|     public function send_new_registration_notification( $user_id, $registration_data ) {
 | |
|         $user = get_userdata( $user_id );
 | |
|         if ( ! $user ) {
 | |
|             return false;
 | |
|         }
 | |
|         
 | |
|         // Get notification emails
 | |
|         $options = get_option( 'hvac_ce_options', array() );
 | |
|         $notification_emails = isset( $options['notification_emails'] ) ? $options['notification_emails'] : get_option( 'admin_email' );
 | |
|         
 | |
|         // Convert comma-separated list to array
 | |
|         if ( is_string( $notification_emails ) ) {
 | |
|             $notification_emails = array_map( 'trim', explode( ',', $notification_emails ) );
 | |
|         }
 | |
|         
 | |
|         // Generate approval token
 | |
|         $approval_token = $this->generate_approval_token( $user_id );
 | |
|         update_user_meta( $user_id, 'hvac_approval_token', $approval_token );
 | |
|         
 | |
|         // Build approval URL
 | |
|         $approval_url = add_query_arg( array(
 | |
|             'hvac_approve_trainer' => $user_id,
 | |
|             'hvac_approval_token' => $approval_token,
 | |
|         ), home_url( '/master-trainer/dashboard/' ) );
 | |
|         
 | |
|         // Get email template
 | |
|         $template = $this->get_email_template( 'new_registration' );
 | |
|         
 | |
|         // Replace placeholders
 | |
|         $replacements = array(
 | |
|             '{trainer_name}' => $user->display_name,
 | |
|             '{trainer_email}' => $user->user_email,
 | |
|             '{business_name}' => get_user_meta( $user_id, 'business_name', true ),
 | |
|             '{business_phone}' => get_user_meta( $user_id, 'business_phone', true ),
 | |
|             '{business_email}' => get_user_meta( $user_id, 'business_email', true ),
 | |
|             '{registration_date}' => date( 'F j, Y', strtotime( $user->user_registered ) ),
 | |
|             '{application_details}' => get_user_meta( $user_id, 'application_details', true ),
 | |
|             '{approval_url}' => $approval_url,
 | |
|             '{website_name}' => get_bloginfo( 'name' ),
 | |
|             '{website_url}' => home_url(),
 | |
|         );
 | |
|         
 | |
|         $subject = str_replace( array_keys( $replacements ), array_values( $replacements ), $template['subject'] );
 | |
|         $message = str_replace( array_keys( $replacements ), array_values( $replacements ), $template['body'] );
 | |
|         
 | |
|         // Send emails
 | |
|         $headers = array( 'Content-Type: text/html; charset=UTF-8' );
 | |
|         
 | |
|         foreach ( $notification_emails as $email ) {
 | |
|             wp_mail( $email, $subject, $message, $headers );
 | |
|         }
 | |
|         
 | |
|         return true;
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Send approval notification to trainer
 | |
|      *
 | |
|      * @param int $user_id User ID
 | |
|      */
 | |
|     public function send_approval_notification( $user_id ) {
 | |
|         $user = get_userdata( $user_id );
 | |
|         if ( ! $user ) {
 | |
|             return false;
 | |
|         }
 | |
|         
 | |
|         // Get email template
 | |
|         $template = $this->get_email_template( 'account_approved' );
 | |
|         
 | |
|         // Replace placeholders
 | |
|         $replacements = array(
 | |
|             '{trainer_name}' => $user->display_name,
 | |
|             '{trainer_email}' => $user->user_email,
 | |
|             '{business_name}' => get_user_meta( $user_id, 'business_name', true ),
 | |
|             '{dashboard_url}' => home_url( '/trainer/dashboard/' ),
 | |
|             '{login_url}' => home_url( '/community-login/' ),
 | |
|             '{website_name}' => get_bloginfo( 'name' ),
 | |
|             '{website_url}' => home_url(),
 | |
|             '{current_date}' => date( 'F j, Y' ),
 | |
|         );
 | |
|         
 | |
|         $subject = str_replace( array_keys( $replacements ), array_values( $replacements ), $template['subject'] );
 | |
|         $message = str_replace( array_keys( $replacements ), array_values( $replacements ), $template['body'] );
 | |
|         
 | |
|         // Send email
 | |
|         $headers = array( 'Content-Type: text/html; charset=UTF-8' );
 | |
|         
 | |
|         return wp_mail( $user->user_email, $subject, $message, $headers );
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Send disabled notification to trainer
 | |
|      *
 | |
|      * @param int $user_id User ID
 | |
|      */
 | |
|     public function send_disabled_notification( $user_id ) {
 | |
|         $user = get_userdata( $user_id );
 | |
|         if ( ! $user ) {
 | |
|             return false;
 | |
|         }
 | |
|         
 | |
|         // Get email template
 | |
|         $template = $this->get_email_template( 'account_disabled' );
 | |
|         
 | |
|         // Replace placeholders
 | |
|         $replacements = array(
 | |
|             '{trainer_name}' => $user->display_name,
 | |
|             '{trainer_email}' => $user->user_email,
 | |
|             '{business_name}' => get_user_meta( $user_id, 'business_name', true ),
 | |
|             '{support_email}' => get_option( 'admin_email' ),
 | |
|             '{website_name}' => get_bloginfo( 'name' ),
 | |
|             '{website_url}' => home_url(),
 | |
|             '{current_date}' => date( 'F j, Y' ),
 | |
|         );
 | |
|         
 | |
|         $subject = str_replace( array_keys( $replacements ), array_values( $replacements ), $template['subject'] );
 | |
|         $message = str_replace( array_keys( $replacements ), array_values( $replacements ), $template['body'] );
 | |
|         
 | |
|         // Send email
 | |
|         $headers = array( 'Content-Type: text/html; charset=UTF-8' );
 | |
|         
 | |
|         return wp_mail( $user->user_email, $subject, $message, $headers );
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Get email template
 | |
|      *
 | |
|      * @param string $template_key Template key
 | |
|      * @return array Template data with subject and body
 | |
|      */
 | |
|     private function get_email_template( $template_key ) {
 | |
|         $options = get_option( 'hvac_ce_email_templates', array() );
 | |
|         
 | |
|         // Default templates
 | |
|         $defaults = array(
 | |
|             'new_registration' => array(
 | |
|                 'subject' => 'New HVAC Trainer Registration - {trainer_name}',
 | |
|                 'body' => '
 | |
|                     <h2>New Trainer Registration Pending Approval</h2>
 | |
|                     <p>A new HVAC trainer has registered and is awaiting approval.</p>
 | |
|                     
 | |
|                     <h3>Trainer Details:</h3>
 | |
|                     <ul>
 | |
|                         <li><strong>Name:</strong> {trainer_name}</li>
 | |
|                         <li><strong>Email:</strong> {trainer_email}</li>
 | |
|                         <li><strong>Business:</strong> {business_name}</li>
 | |
|                         <li><strong>Phone:</strong> {business_phone}</li>
 | |
|                         <li><strong>Business Email:</strong> {business_email}</li>
 | |
|                         <li><strong>Registration Date:</strong> {registration_date}</li>
 | |
|                     </ul>
 | |
|                     
 | |
|                     <h3>Application Details:</h3>
 | |
|                     <p>{application_details}</p>
 | |
|                     
 | |
|                     <p><a href="{approval_url}" style="display: inline-block; padding: 10px 20px; background: #0073aa; color: white; text-decoration: none; border-radius: 4px;">Approve This Trainer</a></p>
 | |
|                     
 | |
|                     <p>Or copy this link: {approval_url}</p>
 | |
|                 ',
 | |
|             ),
 | |
|             'account_approved' => array(
 | |
|                 'subject' => 'Your HVAC Trainer Account Has Been Approved!',
 | |
|                 'body' => '
 | |
|                     <h2>Welcome to {website_name}!</h2>
 | |
|                     
 | |
|                     <p>Dear {trainer_name},</p>
 | |
|                     
 | |
|                     <p>Great news! Your HVAC trainer account has been approved and you now have full access to create and manage training events.</p>
 | |
|                     
 | |
|                     <h3>What You Can Do Now:</h3>
 | |
|                     <ul>
 | |
|                         <li>Create and manage training events</li>
 | |
|                         <li>Access your trainer dashboard</li>
 | |
|                         <li>Generate certificates for attendees</li>
 | |
|                         <li>Communicate with your attendees</li>
 | |
|                         <li>View analytics and reports</li>
 | |
|                     </ul>
 | |
|                     
 | |
|                     <h3>Getting Started:</h3>
 | |
|                     <ol>
 | |
|                         <li><a href="{login_url}">Log in to your account</a></li>
 | |
|                         <li>Visit your <a href="{dashboard_url}">Trainer Dashboard</a></li>
 | |
|                         <li>Click "Create New Event" to post your first training event</li>
 | |
|                         <li>Share your event with your network to maximize attendance</li>
 | |
|                     </ol>
 | |
|                     
 | |
|                     <p>If you have any questions or need assistance, please don\'t hesitate to reach out to our support team.</p>
 | |
|                     
 | |
|                     <p>We\'re excited to have you as part of our training community!</p>
 | |
|                     
 | |
|                     <p>Best regards,<br>
 | |
|                     The {website_name} Team</p>
 | |
|                 ',
 | |
|             ),
 | |
|             'account_disabled' => array(
 | |
|                 'subject' => 'Your HVAC Trainer Account Has Been Disabled',
 | |
|                 'body' => '
 | |
|                     <h2>Account Status Update</h2>
 | |
|                     
 | |
|                     <p>Dear {trainer_name},</p>
 | |
|                     
 | |
|                     <p>We regret to inform you that your HVAC trainer account on {website_name} has been disabled.</p>
 | |
|                     
 | |
|                     <p>Your account may have been disabled for one of the following reasons:</p>
 | |
|                     <ul>
 | |
|                         <li>Violation of our terms of service or community guidelines</li>
 | |
|                         <li>Extended period of inactivity</li>
 | |
|                         <li>Incomplete or inaccurate information</li>
 | |
|                         <li>Quality concerns or complaints</li>
 | |
|                     </ul>
 | |
|                     
 | |
|                     <p>If you believe this action was taken in error or would like to discuss reactivating your account, please contact our support team at <a href="mailto:{support_email}">{support_email}</a>.</p>
 | |
|                     
 | |
|                     <p>We appreciate your understanding.</p>
 | |
|                     
 | |
|                     <p>Sincerely,<br>
 | |
|                     The {website_name} Team</p>
 | |
|                 ',
 | |
|             ),
 | |
|         );
 | |
|         
 | |
|         // Return custom template if exists, otherwise default
 | |
|         if ( isset( $options[$template_key] ) ) {
 | |
|             return $options[$template_key];
 | |
|         }
 | |
|         
 | |
|         return isset( $defaults[$template_key] ) ? $defaults[$template_key] : array( 'subject' => '', 'body' => '' );
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Generate approval token
 | |
|      *
 | |
|      * @param int $user_id User ID
 | |
|      * @return string Token
 | |
|      */
 | |
|     private function generate_approval_token( $user_id ) {
 | |
|         return wp_hash( $user_id . time() . wp_rand() );
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * Handle approval request from email link
 | |
|      */
 | |
|     public function handle_approval_request() {
 | |
|         $user_id = get_query_var( 'hvac_approve_trainer' );
 | |
|         $token = get_query_var( 'hvac_approval_token' );
 | |
|         
 | |
|         if ( ! $user_id || ! $token ) {
 | |
|             return;
 | |
|         }
 | |
|         
 | |
|         // Verify token
 | |
|         $stored_token = get_user_meta( $user_id, 'hvac_approval_token', true );
 | |
|         
 | |
|         if ( $token !== $stored_token ) {
 | |
|             wp_die( __( 'Invalid approval token.', 'hvac-community-events' ) );
 | |
|         }
 | |
|         
 | |
|         // Check if user is logged in
 | |
|         if ( ! is_user_logged_in() ) {
 | |
|             // Store approval request in session/transient
 | |
|             set_transient( 'hvac_pending_approval_' . $token, $user_id, HOUR_IN_SECONDS );
 | |
|             
 | |
|             // Redirect to login with return URL
 | |
|             $login_url = add_query_arg( array(
 | |
|                 'redirect_to' => urlencode( add_query_arg( array(
 | |
|                     'hvac_approve_trainer' => $user_id,
 | |
|                     'hvac_approval_token' => $token,
 | |
|                 ), home_url( '/master-trainer/dashboard/' ) ) ),
 | |
|             ), home_url( '/community-login/' ) );
 | |
|             
 | |
|             wp_redirect( $login_url );
 | |
|             exit;
 | |
|         }
 | |
|         
 | |
|         // Check if current user can approve trainers
 | |
|         if ( ! current_user_can( 'view_master_dashboard' ) && ! current_user_can( 'manage_options' ) ) {
 | |
|             wp_die( __( 'You do not have permission to approve trainers.', 'hvac-community-events' ) );
 | |
|         }
 | |
|         
 | |
|         // Approve the trainer
 | |
|         if ( ! class_exists( 'HVAC_Trainer_Status' ) ) {
 | |
|             require_once HVAC_PLUGIN_DIR . 'includes/class-hvac-trainer-status.php';
 | |
|         }
 | |
|         
 | |
|         $result = HVAC_Trainer_Status::set_trainer_status( $user_id, HVAC_Trainer_Status::STATUS_APPROVED );
 | |
|         
 | |
|         if ( $result ) {
 | |
|             // Delete the token
 | |
|             delete_user_meta( $user_id, 'hvac_approval_token' );
 | |
|             
 | |
|             // Get trainer info for message
 | |
|             $trainer = get_userdata( $user_id );
 | |
|             $message = sprintf(
 | |
|                 __( 'Trainer %s with email %s has been approved!', 'hvac-community-events' ),
 | |
|                 $trainer->display_name,
 | |
|                 $trainer->user_email
 | |
|             );
 | |
|             
 | |
|             // Store success message in transient
 | |
|             set_transient( 'hvac_approval_message', $message, 30 );
 | |
|         }
 | |
|         
 | |
|         // Redirect to master dashboard
 | |
|         wp_redirect( home_url( '/master-trainer/dashboard/' ) );
 | |
|         exit;
 | |
|     }
 | |
|     
 | |
|     /**
 | |
|      * AJAX handler for bulk status updates
 | |
|      */
 | |
|     public function ajax_bulk_update_status() {
 | |
|         // Check nonce
 | |
|         if ( ! isset( $_POST['nonce'] ) || ! wp_verify_nonce( $_POST['nonce'], 'hvac_master_dashboard_nonce' ) ) {
 | |
|             wp_die( 'Security check failed' );
 | |
|         }
 | |
|         
 | |
|         // Check permissions
 | |
|         if ( ! current_user_can( 'view_master_dashboard' ) && ! current_user_can( 'manage_options' ) ) {
 | |
|             wp_send_json_error( array( 'message' => 'Insufficient permissions' ) );
 | |
|         }
 | |
|         
 | |
|         // Get parameters
 | |
|         $user_ids = isset( $_POST['user_ids'] ) ? array_map( 'intval', $_POST['user_ids'] ) : array();
 | |
|         $new_status = isset( $_POST['status'] ) ? sanitize_text_field( $_POST['status'] ) : '';
 | |
|         
 | |
|         if ( empty( $user_ids ) || empty( $new_status ) ) {
 | |
|             wp_send_json_error( array( 'message' => 'Missing required parameters' ) );
 | |
|         }
 | |
|         
 | |
|         // Load status class
 | |
|         if ( ! class_exists( 'HVAC_Trainer_Status' ) ) {
 | |
|             require_once HVAC_PLUGIN_DIR . 'includes/class-hvac-trainer-status.php';
 | |
|         }
 | |
|         
 | |
|         // Perform bulk update
 | |
|         $results = HVAC_Trainer_Status::bulk_update_status( $user_ids, $new_status );
 | |
|         
 | |
|         if ( $results['success'] > 0 ) {
 | |
|             wp_send_json_success( array(
 | |
|                 'message' => sprintf(
 | |
|                     __( 'Successfully updated %d trainer(s). %d failed.', 'hvac-community-events' ),
 | |
|                     $results['success'],
 | |
|                     $results['failed']
 | |
|                 ),
 | |
|                 'results' => $results,
 | |
|             ) );
 | |
|         } else {
 | |
|             wp_send_json_error( array(
 | |
|                 'message' => __( 'Failed to update trainer statuses.', 'hvac-community-events' ),
 | |
|                 'results' => $results,
 | |
|             ) );
 | |
|         }
 | |
|     }
 | |
| } |