- 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;
|
|
}
|
|
} |