- Fixed dashboard data class to use consistent post_author queries instead of mixed _EventOrganizerID meta queries - This resolves the issue where dashboard showed 18 events but 0 tickets/revenue - Added WordPress API credentials to environment (.env) - Created comprehensive API debugging utilities (wp-api-debug.sh, wp-api-fix.sh, api-only-debug.sh) - Enhanced test and deployment suite with WordPress REST API capabilities - Root cause: get_total_tickets_sold() and get_total_revenue() were using _EventOrganizerID while other methods used post_author 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
516 lines
No EOL
17 KiB
Bash
Executable file
516 lines
No EOL
17 KiB
Bash
Executable file
#!/bin/bash
|
|
|
|
# Exit on error
|
|
set -e
|
|
|
|
# Source environment variables
|
|
if [ -f ".env" ]; then
|
|
source .env
|
|
else
|
|
echo "Error: .env file not found. Please create it with the required variables."
|
|
exit 1
|
|
fi
|
|
|
|
echo "===== Uploading Corrected Dashboard Data Class ====="
|
|
|
|
# Create corrected dashboard data class content
|
|
CORRECTED_CLASS='<?php
|
|
/**
|
|
* HVAC Community Events Dashboard Data Handler
|
|
*
|
|
* Retrieves and calculates data needed for the Trainer Dashboard.
|
|
*
|
|
* @package HVAC Community Events
|
|
* @subpackage Includes
|
|
* @author Roo
|
|
* @version 1.0.0
|
|
*/
|
|
|
|
// Exit if accessed directly.
|
|
if ( ! defined( "ABSPATH" ) ) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Class HVAC_Dashboard_Data
|
|
*
|
|
* Handles fetching and processing data for the trainer dashboard.
|
|
*/
|
|
class HVAC_Dashboard_Data {
|
|
|
|
/**
|
|
* The ID of the trainer user.
|
|
*
|
|
* @var int
|
|
*/
|
|
private int $user_id;
|
|
|
|
/**
|
|
* Constructor.
|
|
*
|
|
* @param int $user_id The ID of the trainer user.
|
|
*/
|
|
public function __construct( int $user_id ) {
|
|
$this->user_id = $user_id;
|
|
}
|
|
|
|
/**
|
|
* Get the total number of events created by the trainer.
|
|
*
|
|
* @return int
|
|
*/
|
|
public function get_total_events_count() : int {
|
|
global $wpdb;
|
|
|
|
// Use direct database query to avoid TEC query hijacking
|
|
$count = $wpdb->get_var( $wpdb->prepare(
|
|
"SELECT COUNT(*) 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;
|
|
}
|
|
|
|
/**
|
|
* Get the number of upcoming events for the trainer.
|
|
*
|
|
* @return int
|
|
*/
|
|
public function get_upcoming_events_count() : int {
|
|
global $wpdb;
|
|
$today = date( "Y-m-d H:i:s" );
|
|
|
|
// Use direct database query to avoid TEC query hijacking
|
|
$count = $wpdb->get_var( $wpdb->prepare(
|
|
"SELECT COUNT(*) FROM {$wpdb->posts} p
|
|
LEFT JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id AND pm.meta_key = \"_EventStartDate\"
|
|
WHERE p.post_type = %s
|
|
AND p.post_author = %d
|
|
AND p.post_status IN (\"publish\", \"future\")
|
|
AND (pm.meta_value >= %s OR pm.meta_value IS NULL)",
|
|
Tribe__Events__Main::POSTTYPE,
|
|
$this->user_id,
|
|
$today
|
|
) );
|
|
|
|
return (int) $count;
|
|
}
|
|
|
|
/**
|
|
* Get the number of past events for the trainer.
|
|
*
|
|
* @return int
|
|
*/
|
|
public function get_past_events_count() : int {
|
|
global $wpdb;
|
|
$today = date( "Y-m-d H:i:s" );
|
|
|
|
// Use direct database query to avoid TEC query hijacking
|
|
$count = $wpdb->get_var( $wpdb->prepare(
|
|
"SELECT COUNT(*) FROM {$wpdb->posts} p
|
|
LEFT JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id AND pm.meta_key = \"_EventEndDate\"
|
|
WHERE p.post_type = %s
|
|
AND p.post_author = %d
|
|
AND p.post_status IN (\"publish\", \"private\")
|
|
AND pm.meta_value < %s",
|
|
Tribe__Events__Main::POSTTYPE,
|
|
$this->user_id,
|
|
$today
|
|
) );
|
|
|
|
return (int) $count;
|
|
}
|
|
|
|
/**
|
|
* Get the total number of tickets sold across all the trainer\'s events.
|
|
*
|
|
* @return int
|
|
*/
|
|
public function get_total_tickets_sold() : int {
|
|
$total_tickets = 0;
|
|
$args = array(
|
|
"post_type" => Tribe__Events__Main::POSTTYPE,
|
|
"author" => $this->user_id, // Use post_author instead of meta query
|
|
"post_status" => array( "publish", "future", "draft", "pending", "private" ),
|
|
"posts_per_page" => -1,
|
|
"fields" => "ids",
|
|
);
|
|
$event_ids = get_posts( $args );
|
|
|
|
if ( ! empty( $event_ids ) ) {
|
|
foreach ( $event_ids as $event_id ) {
|
|
// Check both meta keys that might store sold count
|
|
$sold = get_post_meta( $event_id, "_tribe_tickets_sold", true );
|
|
if (!is_numeric($sold)) {
|
|
// Try alternative meta key used in the test script
|
|
$sold = get_post_meta( $event_id, "_tribe_ticket_sold_count", true );
|
|
}
|
|
|
|
if ( is_numeric( $sold ) ) {
|
|
$total_tickets += (int) $sold;
|
|
} else {
|
|
// If no sold count metadata found, count attendees directly
|
|
$attendees_count = $this->count_event_attendees($event_id);
|
|
if ($attendees_count > 0) {
|
|
$total_tickets += $attendees_count;
|
|
// Update the meta for future reference
|
|
update_post_meta($event_id, "_tribe_tickets_sold", $attendees_count);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $total_tickets;
|
|
}
|
|
|
|
/**
|
|
* Get the total revenue generated across all the trainer\'s events.
|
|
*
|
|
* @return float
|
|
*/
|
|
public function get_total_revenue() : float {
|
|
$total_revenue = 0.0;
|
|
$args = array(
|
|
"post_type" => Tribe__Events__Main::POSTTYPE,
|
|
"author" => $this->user_id, // Use post_author instead of meta query
|
|
"post_status" => array( "publish", "future", "draft", "pending", "private" ),
|
|
"posts_per_page" => -1,
|
|
"fields" => "ids",
|
|
);
|
|
$event_ids = get_posts( $args );
|
|
|
|
if ( ! empty( $event_ids ) ) {
|
|
foreach ( $event_ids as $event_id ) {
|
|
// Event Tickets Plus often stores total revenue in "_tribe_revenue_total" meta
|
|
$revenue = get_post_meta( $event_id, "_tribe_revenue_total", true );
|
|
if ( is_numeric( $revenue ) ) {
|
|
$total_revenue += (float) $revenue;
|
|
} else {
|
|
// Calculate revenue from attendees if meta not found
|
|
$event_revenue = $this->calculate_event_revenue($event_id);
|
|
if ($event_revenue > 0) {
|
|
$total_revenue += $event_revenue;
|
|
// Update the meta for future reference
|
|
update_post_meta($event_id, "_tribe_revenue_total", $event_revenue);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return $total_revenue;
|
|
}
|
|
|
|
/**
|
|
* Get the annual revenue target set by the trainer.
|
|
*
|
|
* @return float|null Returns the target as a float, or null if not set.
|
|
*/
|
|
public 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 the data needed for the events table on the dashboard.
|
|
*
|
|
* @param string $filter_status The status to filter events by ("all", "publish", "future", "draft", "pending", "private"). Defaults to "all".
|
|
* @return array An array of event data arrays/objects, each containing keys like: id, status, name, link, date, organizer, capacity, sold, revenue.
|
|
*/
|
|
public function get_events_table_data( string $filter_status = "all" ) : array {
|
|
$events_data = [];
|
|
$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 );
|
|
|
|
$args = array(
|
|
"post_type" => Tribe__Events__Main::POSTTYPE,
|
|
"author" => $this->user_id, // Query by post author
|
|
"post_status" => $post_status,
|
|
"posts_per_page" => -1,
|
|
"orderby" => "meta_value", // Order by start date
|
|
"meta_key" => "_EventStartDate", // Specify the meta key for ordering
|
|
"order" => "DESC", // Show most recent first
|
|
);
|
|
|
|
$query = new WP_Query( $args );
|
|
|
|
if ( $query->have_posts() ) {
|
|
while ( $query->have_posts() ) {
|
|
$query->the_post();
|
|
$event_id = get_the_ID();
|
|
|
|
// Get Capacity - Sum capacity of all tickets for this event
|
|
$total_capacity = 0;
|
|
if ( function_exists( "tribe_get_tickets" ) ) {
|
|
$tickets = tribe_get_tickets( $event_id );
|
|
if ( $tickets ) {
|
|
foreach ( $tickets as $ticket ) {
|
|
$capacity = $ticket->capacity();
|
|
// -1 often means unlimited capacity for Tribe Tickets
|
|
if ( $capacity === -1 ) {
|
|
$total_capacity = -1; // Mark as unlimited
|
|
break; // No need to sum further if one is unlimited
|
|
}
|
|
if ( is_numeric( $capacity ) ) {
|
|
$total_capacity += $capacity;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get sold and revenue counts, checking for both standard and alternative meta fields
|
|
$sold = get_post_meta( $event_id, "_tribe_tickets_sold", true );
|
|
if (!is_numeric($sold)) {
|
|
$sold = get_post_meta( $event_id, "_tribe_ticket_sold_count", true );
|
|
|
|
// If still no valid count, calculate from attendees
|
|
if (!is_numeric($sold)) {
|
|
$sold = $this->count_event_attendees($event_id);
|
|
if ($sold > 0) {
|
|
update_post_meta($event_id, "_tribe_tickets_sold", $sold);
|
|
}
|
|
}
|
|
}
|
|
|
|
$revenue = get_post_meta( $event_id, "_tribe_revenue_total", true );
|
|
if (!is_numeric($revenue)) {
|
|
$revenue = $this->calculate_event_revenue($event_id);
|
|
if ($revenue > 0) {
|
|
update_post_meta($event_id, "_tribe_revenue_total", $revenue);
|
|
}
|
|
}
|
|
|
|
$events_data[] = array(
|
|
"id" => $event_id,
|
|
"status" => get_post_status( $event_id ),
|
|
"name" => get_the_title(),
|
|
// Return raw data instead of calling TEC functions here
|
|
"link" => get_permalink( $event_id ), // Use standard WP permalink
|
|
"start_date_ts" => strtotime( get_post_meta( $event_id, "_EventStartDate", true ) ), // Return timestamp
|
|
"organizer_id" => (int) get_post_meta( $event_id, "_EventOrganizerID", true ), // Return organizer ID
|
|
"capacity" => ( $total_capacity === -1 ) ? "Unlimited" : (int) $total_capacity,
|
|
"sold" => is_numeric( $sold ) ? (int) $sold : 0,
|
|
"revenue" => is_numeric( $revenue ) ? (float) $revenue : 0.0,
|
|
);
|
|
}
|
|
wp_reset_postdata(); // Restore original Post Data
|
|
}
|
|
|
|
return $events_data;
|
|
}
|
|
|
|
/**
|
|
* Count the number of attendees for an event by querying attendee posts
|
|
*
|
|
* @param int $event_id Event ID to count attendees for
|
|
* @return int Number of attendees found
|
|
*/
|
|
private function count_event_attendees(int $event_id) : int {
|
|
$attendee_count = 0;
|
|
|
|
// Check if Event Tickets is active
|
|
if (class_exists("Tribe__Tickets__Tickets_Handler") && method_exists(Tribe__Tickets__Tickets_Handler::instance(), "get_attendees_by_id")) {
|
|
$attendees = Tribe__Tickets__Tickets_Handler::instance()->get_attendees_by_id($event_id);
|
|
if (is_array($attendees)) {
|
|
$attendee_count = count($attendees);
|
|
}
|
|
} else {
|
|
// Fallback to direct query if Event Tickets not available
|
|
$attendees_query = new WP_Query([
|
|
"post_type" => "tribe_tpp_attendees",
|
|
"posts_per_page" => -1,
|
|
"fields" => "ids",
|
|
"meta_query" => [
|
|
[
|
|
"key" => "_tribe_tpp_event",
|
|
"value" => $event_id,
|
|
"compare" => "=",
|
|
],
|
|
],
|
|
]);
|
|
$attendee_count = $attendees_query->found_posts;
|
|
}
|
|
|
|
return $attendee_count;
|
|
}
|
|
|
|
/**
|
|
* Calculate total revenue for an event by summing ticket prices
|
|
*
|
|
* @param int $event_id Event ID to calculate revenue for
|
|
* @return float Total revenue calculated
|
|
*/
|
|
private function calculate_event_revenue(int $event_id) : float {
|
|
$total_revenue = 0.0;
|
|
|
|
// Check if Event Tickets is active
|
|
if (class_exists("Tribe__Tickets__Tickets_Handler") && method_exists(Tribe__Tickets__Tickets_Handler::instance(), "get_attendees_by_id")) {
|
|
$attendees = Tribe__Tickets__Tickets_Handler::instance()->get_attendees_by_id($event_id);
|
|
|
|
if (is_array($attendees)) {
|
|
foreach ($attendees as $attendee) {
|
|
// Extract price - structure might vary based on ticket provider
|
|
$price = 0;
|
|
if (isset($attendee["price"]) && is_numeric($attendee["price"])) {
|
|
$price = (float)$attendee["price"];
|
|
} elseif (isset($attendee["price_paid"]) && is_numeric($attendee["price_paid"])) {
|
|
$price = (float)$attendee["price_paid"];
|
|
}
|
|
|
|
$total_revenue += $price;
|
|
}
|
|
}
|
|
} else {
|
|
// Fallback to direct calculation if Event Tickets not available
|
|
// First get all tickets for this event to get prices
|
|
$tickets_query = new WP_Query([
|
|
"post_type" => "tribe_tpp_tickets",
|
|
"posts_per_page" => -1,
|
|
"meta_query" => [
|
|
[
|
|
"key" => "_tribe_tpp_for_event",
|
|
"value" => $event_id,
|
|
"compare" => "=",
|
|
],
|
|
],
|
|
]);
|
|
|
|
if ($tickets_query->have_posts()) {
|
|
while ($tickets_query->have_posts()) {
|
|
$tickets_query->the_post();
|
|
$ticket_id = get_the_ID();
|
|
$price = get_post_meta($ticket_id, "_price", true);
|
|
$sold = get_post_meta($ticket_id, "_tribe_tpp_sold", true);
|
|
|
|
if (is_numeric($price) && is_numeric($sold)) {
|
|
$total_revenue += ((float)$price * (int)$sold);
|
|
}
|
|
}
|
|
wp_reset_postdata();
|
|
}
|
|
}
|
|
|
|
return $total_revenue;
|
|
}
|
|
} // End class HVAC_Dashboard_Data'
|
|
|
|
# Create corrected dashboard class on server
|
|
sshpass -p "$UPSKILL_STAGING_PASS" ssh -o StrictHostKeyChecking=no "$UPSKILL_STAGING_SSH_USER@$UPSKILL_STAGING_IP" "cd $UPSKILL_STAGING_PATH && cat > wp-content/plugins/hvac-community-events/includes/class-hvac-dashboard-data.php << 'EOF'
|
|
$CORRECTED_CLASS
|
|
EOF"
|
|
|
|
echo "Uploaded corrected dashboard data class"
|
|
|
|
# Test the corrected class
|
|
TEST_SCRIPT="<?php
|
|
require_once('wp-load.php');
|
|
|
|
echo \"Testing corrected dashboard data class...\\n\";
|
|
|
|
\$user = get_user_by('login', 'test_trainer');
|
|
if (\$user) {
|
|
\$dashboard_data = new HVAC_Dashboard_Data(\$user->ID);
|
|
|
|
\$total_events = \$dashboard_data->get_total_events_count();
|
|
\$upcoming_events = \$dashboard_data->get_upcoming_events_count();
|
|
\$past_events = \$dashboard_data->get_past_events_count();
|
|
\$total_tickets = \$dashboard_data->get_total_tickets_sold();
|
|
\$total_revenue = \$dashboard_data->get_total_revenue();
|
|
|
|
echo \"Dashboard Data Results:\\n\";
|
|
echo \"- Total Events: {\$total_events}\\n\";
|
|
echo \"- Upcoming Events: {\$upcoming_events}\\n\";
|
|
echo \"- Past Events: {\$past_events}\\n\";
|
|
echo \"- Total Tickets: {\$total_tickets}\\n\";
|
|
echo \"- Total Revenue: {\$total_revenue}\\n\";
|
|
|
|
// Run test data creation if no events found
|
|
if (\$total_events == 0) {
|
|
echo \"\\nNo events found, running test data creation...\\n\";
|
|
// Use our create-test-data-working script content inline
|
|
exec('cd /home/974670.cloudwaysapps.com/uberrxmprk/public_html && php -r \"
|
|
// Load WordPress
|
|
require_once(\\\"wp-load.php\\\");
|
|
|
|
echo \\\"Creating test data for test_trainer...\\\\n\\\";
|
|
|
|
// Get test_trainer user
|
|
\\\$user = get_user_by(\\\"login\\\", \\\"test_trainer\\\");
|
|
if (!\\\$user) {
|
|
echo \\\"Error: test_trainer user not found\\\\n\\\";
|
|
exit;
|
|
}
|
|
|
|
echo \\\"User ID: {\\\$user->ID}\\\\n\\\";
|
|
|
|
// Create 3 test events
|
|
for (\\\$i = 1; \\\$i <= 3; \\\$i++) {
|
|
\\\$event_id = wp_insert_post(array(
|
|
\\\"post_title\\\" => \\\"Test Training Event \\\$i\\\",
|
|
\\\"post_content\\\" => \\\"This is test training event number \\\$i for demo purposes.\\\",
|
|
\\\"post_status\\\" => \\\"publish\\\",
|
|
\\\"post_type\\\" => \\\"tribe_events\\\",
|
|
\\\"post_author\\\" => \\\$user->ID
|
|
));
|
|
|
|
if (\\\$event_id) {
|
|
// Add event meta
|
|
\\\$start_date = date(\\\"Y-m-d H:i:s\\\", strtotime(\\\"+\\\$i weeks\\\"));
|
|
\\\$end_date = date(\\\"Y-m-d H:i:s\\\", strtotime(\\\"+\\\$i weeks +4 hours\\\"));
|
|
|
|
update_post_meta(\\\$event_id, \\\"_EventStartDate\\\", \\\$start_date);
|
|
update_post_meta(\\\$event_id, \\\"_EventEndDate\\\", \\\$end_date);
|
|
update_post_meta(\\\$event_id, \\\"_EventOrganizerID\\\", \\\$user->ID);
|
|
|
|
// Add some test ticket sales data
|
|
\\\$sold_count = rand(5, 20);
|
|
\\\$price = rand(50, 200);
|
|
\\\$revenue = \\\$sold_count * \\\$price;
|
|
|
|
update_post_meta(\\\$event_id, \\\"_tribe_tickets_sold\\\", \\\$sold_count);
|
|
update_post_meta(\\\$event_id, \\\"_tribe_revenue_total\\\", \\\$revenue);
|
|
|
|
echo \\\"Created event \\\$i with ID: \\\$event_id (Sold: \\\$sold_count, Revenue: \\\$\\\$revenue)\\\\n\\\";
|
|
}
|
|
}
|
|
|
|
echo \\\"Test data creation complete\\\\n\\\";
|
|
\"', \$output, \$return_var);
|
|
|
|
echo implode(\"\\n\", \$output) . \"\\n\";
|
|
|
|
// Test again after creating data
|
|
\$total_events = \$dashboard_data->get_total_events_count();
|
|
\$total_tickets = \$dashboard_data->get_total_tickets_sold();
|
|
\$total_revenue = \$dashboard_data->get_total_revenue();
|
|
|
|
echo \"\\nAfter creating test data:\\n\";
|
|
echo \"- Total Events: {\$total_events}\\n\";
|
|
echo \"- Total Tickets: {\$total_tickets}\\n\";
|
|
echo \"- Total Revenue: {\$total_revenue}\\n\";
|
|
}
|
|
} else {
|
|
echo \"test_trainer user not found\\n\";
|
|
}
|
|
|
|
echo \"\\nTesting complete.\\n\";
|
|
"
|
|
|
|
# Create and run test script
|
|
sshpass -p "$UPSKILL_STAGING_PASS" ssh -o StrictHostKeyChecking=no "$UPSKILL_STAGING_SSH_USER@$UPSKILL_STAGING_IP" "cd $UPSKILL_STAGING_PATH && cat > test-dashboard.php << 'EOF'
|
|
$TEST_SCRIPT
|
|
EOF"
|
|
|
|
echo -e "\nTesting the corrected dashboard class..."
|
|
sshpass -p "$UPSKILL_STAGING_PASS" ssh -o StrictHostKeyChecking=no "$UPSKILL_STAGING_SSH_USER@$UPSKILL_STAGING_IP" "cd $UPSKILL_STAGING_PATH && php test-dashboard.php"
|
|
|
|
# Clean up
|
|
sshpass -p "$UPSKILL_STAGING_PASS" ssh -o StrictHostKeyChecking=no "$UPSKILL_STAGING_SSH_USER@$UPSKILL_STAGING_IP" "cd $UPSKILL_STAGING_PATH && rm test-dashboard.php"
|
|
|
|
echo -e "\n===== Dashboard Data Upload and Test Complete ====="
|
|
echo "Please refresh the dashboard page to see if the data now appears correctly." |