- Added explicit checks to prevent authentication redirects on registration page - Added ensure_registration_page_public() method with priority 1 to run before other auth checks - Included registration-pending and training-login pages in public pages list - Added fallback function in main plugin file to remove auth hooks on registration page This ensures that users can access /trainer/registration/ without being logged in, as intended for new trainer signups.
		
			
				
	
	
		
			335 lines
		
	
	
		
			No EOL
		
	
	
		
			8.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			335 lines
		
	
	
		
			No EOL
		
	
	
		
			8.2 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
| <?php
 | |
| /**
 | |
|  * HVAC Community Events Dashboard Data Handler - Refactored
 | |
|  *
 | |
|  * Optimized version with better caching and query optimization
 | |
|  *
 | |
|  * @package    HVAC_Community_Events
 | |
|  * @subpackage Includes
 | |
|  * @since      1.1.0
 | |
|  */
 | |
| 
 | |
| if ( ! defined( 'ABSPATH' ) ) {
 | |
| 	exit;
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * Class HVAC_Dashboard_Data_Refactored
 | |
|  */
 | |
| class HVAC_Dashboard_Data_Refactored {
 | |
| 
 | |
| 	/**
 | |
| 	 * The ID of the trainer user.
 | |
| 	 *
 | |
| 	 * @var int
 | |
| 	 */
 | |
| 	private int $user_id;
 | |
| 
 | |
| 	/**
 | |
| 	 * Cache group for dashboard data
 | |
| 	 *
 | |
| 	 * @var string
 | |
| 	 */
 | |
| 	private $cache_group = 'hvac_dashboard';
 | |
| 
 | |
| 	/**
 | |
| 	 * Cache expiration time (5 minutes)
 | |
| 	 *
 | |
| 	 * @var int
 | |
| 	 */
 | |
| 	private $cache_expiration = 300;
 | |
| 
 | |
| 	/**
 | |
| 	 * Constructor.
 | |
| 	 *
 | |
| 	 * @param int $user_id The ID of the trainer user.
 | |
| 	 */
 | |
| 	public function __construct( int $user_id ) {
 | |
| 		$this->user_id = $user_id;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Get all dashboard stats in a single cached object
 | |
| 	 *
 | |
| 	 * @return array
 | |
| 	 */
 | |
| 	public function get_all_stats() : array {
 | |
| 		$cache_key = 'stats_' . $this->user_id;
 | |
| 		$stats = wp_cache_get( $cache_key, $this->cache_group );
 | |
| 
 | |
| 		if ( false === $stats ) {
 | |
| 			$stats = array(
 | |
| 				'total_events'    => $this->calculate_total_events_count(),
 | |
| 				'upcoming_events' => $this->calculate_upcoming_events_count(),
 | |
| 				'past_events'     => $this->calculate_past_events_count(),
 | |
| 				'total_tickets'   => $this->calculate_total_tickets_sold(),
 | |
| 				'total_revenue'   => $this->calculate_total_revenue(),
 | |
| 				'revenue_target'  => $this->get_annual_revenue_target(),
 | |
| 			);
 | |
| 
 | |
| 			wp_cache_set( $cache_key, $stats, $this->cache_group, $this->cache_expiration );
 | |
| 			HVAC_Logger::info( 'Dashboard stats calculated and cached', 'Dashboard', array( 'user_id' => $this->user_id ) );
 | |
| 		}
 | |
| 
 | |
| 		return $stats;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Clear cache for a specific user
 | |
| 	 *
 | |
| 	 * @return void
 | |
| 	 */
 | |
| 	public function clear_cache() {
 | |
| 		$cache_key = 'stats_' . $this->user_id;
 | |
| 		wp_cache_delete( $cache_key, $this->cache_group );
 | |
| 		HVAC_Logger::info( 'Dashboard cache cleared', 'Dashboard', array( 'user_id' => $this->user_id ) );
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Calculate total events count (optimized)
 | |
| 	 *
 | |
| 	 * @return int
 | |
| 	 */
 | |
| 	private function calculate_total_events_count() : int {
 | |
| 		global $wpdb;
 | |
| 		
 | |
| 		// Direct query is more efficient for simple counts
 | |
| 		$count = $wpdb->get_var( $wpdb->prepare(
 | |
| 			"SELECT COUNT(ID) FROM {$wpdb->posts} 
 | |
| 			WHERE post_type = %s 
 | |
| 			AND post_author = %d 
 | |
| 			AND post_status IN ('publish', 'future', 'draft', 'pending', 'private')",
 | |
| 			Tribe__Events__Main::POSTTYPE,
 | |
| 			$this->user_id
 | |
| 		) );
 | |
| 
 | |
| 		return (int) $count;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Calculate upcoming events count
 | |
| 	 *
 | |
| 	 * @return int
 | |
| 	 */
 | |
| 	private function calculate_upcoming_events_count() : int {
 | |
| 		global $wpdb;
 | |
| 		
 | |
| 		$today = current_time( 'mysql' );
 | |
| 		
 | |
| 		// Query using post_author and meta data
 | |
| 		$count = $wpdb->get_var( $wpdb->prepare(
 | |
| 			"SELECT COUNT(DISTINCT p.ID) 
 | |
| 			FROM {$wpdb->posts} p
 | |
| 			INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
 | |
| 			WHERE p.post_type = %s 
 | |
| 			AND p.post_author = %d 
 | |
| 			AND p.post_status IN ('publish', 'future')
 | |
| 			AND pm.meta_key = '_EventStartDate'
 | |
| 			AND pm.meta_value >= %s",
 | |
| 			Tribe__Events__Main::POSTTYPE,
 | |
| 			$this->user_id,
 | |
| 			$today
 | |
| 		) );
 | |
| 
 | |
| 		return (int) $count;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Calculate past events count
 | |
| 	 *
 | |
| 	 * @return int
 | |
| 	 */
 | |
| 	private function calculate_past_events_count() : int {
 | |
| 		global $wpdb;
 | |
| 		
 | |
| 		$today = current_time( 'mysql' );
 | |
| 		
 | |
| 		$count = $wpdb->get_var( $wpdb->prepare(
 | |
| 			"SELECT COUNT(DISTINCT p.ID) 
 | |
| 			FROM {$wpdb->posts} p
 | |
| 			INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
 | |
| 			WHERE p.post_type = %s 
 | |
| 			AND p.post_author = %d 
 | |
| 			AND p.post_status IN ('publish', 'private')
 | |
| 			AND pm.meta_key = '_EventEndDate'
 | |
| 			AND pm.meta_value < %s",
 | |
| 			Tribe__Events__Main::POSTTYPE,
 | |
| 			$this->user_id,
 | |
| 			$today
 | |
| 		) );
 | |
| 
 | |
| 		return (int) $count;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Calculate total tickets sold (optimized with single query)
 | |
| 	 *
 | |
| 	 * @return int
 | |
| 	 */
 | |
| 	private function calculate_total_tickets_sold() : int {
 | |
| 		global $wpdb;
 | |
| 		
 | |
| 		// Get all event IDs in one query
 | |
| 		$event_ids = $wpdb->get_col( $wpdb->prepare(
 | |
| 			"SELECT ID FROM {$wpdb->posts} 
 | |
| 			WHERE post_type = %s 
 | |
| 			AND post_author = %d 
 | |
| 			AND post_status IN ('publish', 'future', 'draft', 'pending', 'private')",
 | |
| 			Tribe__Events__Main::POSTTYPE,
 | |
| 			$this->user_id
 | |
| 		) );
 | |
| 
 | |
| 		if ( empty( $event_ids ) ) {
 | |
| 			return 0;
 | |
| 		}
 | |
| 
 | |
| 		// Get sum of tickets sold in one query
 | |
| 		$placeholders = array_fill( 0, count( $event_ids ), '%d' );
 | |
| 		$sql = $wpdb->prepare(
 | |
| 			"SELECT SUM(meta_value) 
 | |
| 			FROM {$wpdb->postmeta} 
 | |
| 			WHERE meta_key = '_tribe_tickets_sold' 
 | |
| 			AND post_id IN (" . implode( ',', $placeholders ) . ")",
 | |
| 			$event_ids
 | |
| 		);
 | |
| 
 | |
| 		$total = $wpdb->get_var( $sql );
 | |
| 
 | |
| 		return (int) $total;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Calculate total revenue (optimized)
 | |
| 	 *
 | |
| 	 * @return float
 | |
| 	 */
 | |
| 	private function calculate_total_revenue() : float {
 | |
| 		global $wpdb;
 | |
| 		
 | |
| 		// Get all event IDs in one query
 | |
| 		$event_ids = $wpdb->get_col( $wpdb->prepare(
 | |
| 			"SELECT ID FROM {$wpdb->posts} 
 | |
| 			WHERE post_type = %s 
 | |
| 			AND post_author = %d 
 | |
| 			AND post_status IN ('publish', 'future', 'draft', 'pending', 'private')",
 | |
| 			Tribe__Events__Main::POSTTYPE,
 | |
| 			$this->user_id
 | |
| 		) );
 | |
| 
 | |
| 		if ( empty( $event_ids ) ) {
 | |
| 			return 0.0;
 | |
| 		}
 | |
| 
 | |
| 		// Get sum of revenue in one query
 | |
| 		$placeholders = array_fill( 0, count( $event_ids ), '%d' );
 | |
| 		$sql = $wpdb->prepare(
 | |
| 			"SELECT SUM(meta_value) 
 | |
| 			FROM {$wpdb->postmeta} 
 | |
| 			WHERE meta_key = '_tribe_revenue_total' 
 | |
| 			AND post_id IN (" . implode( ',', $placeholders ) . ")",
 | |
| 			$event_ids
 | |
| 		);
 | |
| 
 | |
| 		$total = $wpdb->get_var( $sql );
 | |
| 
 | |
| 		return (float) $total;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Get annual revenue target
 | |
| 	 *
 | |
| 	 * @return float|null
 | |
| 	 */
 | |
| 	private function get_annual_revenue_target() : ?float {
 | |
| 		$target = get_user_meta( $this->user_id, 'annual_revenue_target', true );
 | |
| 		return ! empty( $target ) && is_numeric( $target ) ? (float) $target : null;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Get events table data (optimized)
 | |
| 	 *
 | |
| 	 * @param string $filter_status Status filter
 | |
| 	 * @return array
 | |
| 	 */
 | |
| 	public function get_events_table_data( string $filter_status = 'all' ) : array {
 | |
| 		global $wpdb;
 | |
| 
 | |
| 		$valid_statuses = array( 'publish', 'future', 'draft', 'pending', 'private' );
 | |
| 		$post_status = ( 'all' === $filter_status || ! in_array( $filter_status, $valid_statuses, true ) )
 | |
| 					? $valid_statuses
 | |
| 					: array( $filter_status );
 | |
| 
 | |
| 		// Convert to SQL-safe string
 | |
| 		$status_placeholders = array_fill( 0, count( $post_status ), '%s' );
 | |
| 		$status_sql = implode( ',', $status_placeholders );
 | |
| 
 | |
| 		// Get all events with their metadata in fewer queries
 | |
| 		$sql = $wpdb->prepare(
 | |
| 			"SELECT p.ID, p.post_title, p.post_status, p.guid,
 | |
| 				MAX(CASE WHEN pm.meta_key = '_EventStartDate' THEN pm.meta_value END) as start_date,
 | |
| 				MAX(CASE WHEN pm.meta_key = '_EventOrganizerID' THEN pm.meta_value END) as organizer_id,
 | |
| 				MAX(CASE WHEN pm.meta_key = '_tribe_tickets_sold' THEN pm.meta_value END) as tickets_sold,
 | |
| 				MAX(CASE WHEN pm.meta_key = '_tribe_revenue_total' THEN pm.meta_value END) as revenue
 | |
| 			FROM {$wpdb->posts} p
 | |
| 			LEFT JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
 | |
| 			WHERE p.post_type = %s 
 | |
| 			AND p.post_author = %d 
 | |
| 			AND p.post_status IN ($status_sql)
 | |
| 			GROUP BY p.ID
 | |
| 			ORDER BY start_date DESC",
 | |
| 			array_merge(
 | |
| 				array( Tribe__Events__Main::POSTTYPE, $this->user_id ),
 | |
| 				$post_status
 | |
| 			)
 | |
| 		);
 | |
| 
 | |
| 		$events = $wpdb->get_results( $sql );
 | |
| 		$events_data = array();
 | |
| 
 | |
| 		foreach ( $events as $event ) {
 | |
| 			// Get ticket capacity
 | |
| 			$capacity = $this->get_event_capacity( $event->ID );
 | |
| 
 | |
| 			$events_data[] = array(
 | |
| 				'id'        => $event->ID,
 | |
| 				'status'    => $event->post_status,
 | |
| 				'name'      => $event->post_title,
 | |
| 				'link'      => get_permalink( $event->ID ),
 | |
| 				'start_date_ts' => strtotime( $event->start_date ),
 | |
| 				'organizer_id' => (int) $event->organizer_id,
 | |
| 				'capacity'  => $capacity,
 | |
| 				'sold'      => (int) $event->tickets_sold,
 | |
| 				'revenue'   => (float) $event->revenue,
 | |
| 			);
 | |
| 		}
 | |
| 
 | |
| 		return $events_data;
 | |
| 	}
 | |
| 
 | |
| 	/**
 | |
| 	 * Get event capacity
 | |
| 	 *
 | |
| 	 * @param int $event_id Event ID
 | |
| 	 * @return string|int
 | |
| 	 */
 | |
| 	private function get_event_capacity( $event_id ) {
 | |
| 		if ( ! function_exists( 'tribe_get_tickets' ) ) {
 | |
| 			return 0;
 | |
| 		}
 | |
| 
 | |
| 		$tickets = tribe_get_tickets( $event_id );
 | |
| 		$total_capacity = 0;
 | |
| 
 | |
| 		foreach ( $tickets as $ticket ) {
 | |
| 			$capacity = $ticket->capacity();
 | |
| 			if ( $capacity === -1 ) {
 | |
| 				return 'Unlimited';
 | |
| 			}
 | |
| 			if ( is_numeric( $capacity ) ) {
 | |
| 				$total_capacity += $capacity;
 | |
| 			}
 | |
| 		}
 | |
| 
 | |
| 		return $total_capacity;
 | |
| 	}
 | |
| } |