$event_id, 'post_title' => $validated_data['event_title'], 'post_content' => $validated_data['event_description'] ); // Update the event $result = wp_update_post($event_data); if (is_wp_error($result) || !$result) { return new WP_Error('event_update_failed', 'Failed to update event'); } // Update meta fields if (!empty($validated_data['event_start_datetime'])) { update_post_meta($event_id, '_EventStartDate', self::convert_datetime_for_tec($validated_data['event_start_datetime'])); } if (!empty($validated_data['event_end_datetime'])) { update_post_meta($event_id, '_EventEndDate', self::convert_datetime_for_tec($validated_data['event_end_datetime'])); } if (!empty($validated_data['event_timezone'])) { update_post_meta($event_id, '_EventTimezone', $validated_data['event_timezone']); } if (!empty($validated_data['event_capacity'])) { update_post_meta($event_id, '_EventCapacity', absint($validated_data['event_capacity'])); } if (!empty($validated_data['event_cost'])) { update_post_meta($event_id, '_EventCost', floatval($validated_data['event_cost'])); } // Update featured image if provided if (isset($validated_data['event_featured_image'])) { if (!empty($validated_data['event_featured_image'])) { $image_id = absint($validated_data['event_featured_image']); if ($image_id && wp_attachment_is_image($image_id)) { set_post_thumbnail($event_id, $image_id); } } else { // Remove featured image if explicitly cleared delete_post_thumbnail($event_id); } } // Handle venue assignment if (isset($validated_data['venue_ids'])) { if (!empty($validated_data['venue_ids']) && is_array($validated_data['venue_ids'])) { $venue_id = absint($validated_data['venue_ids'][0]); // Single venue if ($venue_id) { update_post_meta($event_id, '_EventVenueID', $venue_id); } } else { delete_post_meta($event_id, '_EventVenueID'); } } // Handle organizer assignment if (isset($validated_data['organizer_ids'])) { if (!empty($validated_data['organizer_ids']) && is_array($validated_data['organizer_ids'])) { $organizer_ids = array_map('absint', $validated_data['organizer_ids']); $organizer_ids = array_filter($organizer_ids); // Remove zeros if (!empty($organizer_ids)) { update_post_meta($event_id, '_EventOrganizerID', $organizer_ids); } } else { delete_post_meta($event_id, '_EventOrganizerID'); } } // Handle category assignment if (isset($validated_data['category_ids'])) { if (!empty($validated_data['category_ids']) && is_array($validated_data['category_ids'])) { $category_ids = array_map('absint', $validated_data['category_ids']); $category_ids = array_filter($category_ids); // Remove zeros if (!empty($category_ids)) { wp_set_object_terms($event_id, $category_ids, 'tribe_events_cat'); } } else { wp_set_object_terms($event_id, array(), 'tribe_events_cat'); } } // Handle ticket data if present if (isset($validated_data['hvac_ticket_data'])) { if (!empty($validated_data['hvac_ticket_data'])) { self::process_ticket_data($event_id, $validated_data['hvac_ticket_data']); } else { delete_post_meta($event_id, '_hvac_ticket_data'); } } // Log the update error_log("HVAC Event Updated: Event ID {$event_id} by user " . get_current_user_id()); return $event_id; } /** * Create a new event from form submission data * * @param array $form_data The submitted form data * @return int|WP_Error Event ID on success, WP_Error on failure */ public static function create_event($form_data) { // Input validation and sanitization $validated_data = self::validate_and_sanitize($form_data); if (is_wp_error($validated_data)) { return $validated_data; } // Create the event post $event_data = array( 'post_title' => $validated_data['event_title'], 'post_content' => $validated_data['event_description'], 'post_type' => 'tribe_events', 'post_status' => 'publish', 'post_author' => get_current_user_id(), 'meta_input' => array() ); // Add event-specific meta data if (!empty($validated_data['event_start_datetime'])) { $event_data['meta_input']['_EventStartDate'] = self::convert_datetime_for_tec($validated_data['event_start_datetime']); } if (!empty($validated_data['event_end_datetime'])) { $event_data['meta_input']['_EventEndDate'] = self::convert_datetime_for_tec($validated_data['event_end_datetime']); } if (!empty($validated_data['event_timezone'])) { $event_data['meta_input']['_EventTimezone'] = $validated_data['event_timezone']; } if (!empty($validated_data['event_capacity'])) { $event_data['meta_input']['_EventCapacity'] = absint($validated_data['event_capacity']); } if (!empty($validated_data['event_cost'])) { $event_data['meta_input']['_EventCost'] = floatval($validated_data['event_cost']); } // Create the event $event_id = wp_insert_post($event_data); if (is_wp_error($event_id) || !$event_id) { return new WP_Error('event_creation_failed', 'Failed to create event'); } // Set featured image if provided if (!empty($validated_data['event_featured_image'])) { $image_id = absint($validated_data['event_featured_image']); if ($image_id && wp_attachment_is_image($image_id)) { set_post_thumbnail($event_id, $image_id); } } // Handle venue assignment if (!empty($validated_data['venue_ids']) && is_array($validated_data['venue_ids'])) { $venue_id = absint($validated_data['venue_ids'][0]); // Single venue if ($venue_id) { update_post_meta($event_id, '_EventVenueID', $venue_id); } } // Handle organizer assignment if (!empty($validated_data['organizer_ids']) && is_array($validated_data['organizer_ids'])) { $organizer_ids = array_map('absint', $validated_data['organizer_ids']); $organizer_ids = array_filter($organizer_ids); // Remove zeros if (!empty($organizer_ids)) { update_post_meta($event_id, '_EventOrganizerID', $organizer_ids); } } // Handle category assignment if (!empty($validated_data['category_ids']) && is_array($validated_data['category_ids'])) { $category_ids = array_map('absint', $validated_data['category_ids']); $category_ids = array_filter($category_ids); // Remove zeros if (!empty($category_ids)) { wp_set_object_terms($event_id, $category_ids, 'tribe_events_cat'); } } // Handle ticket data if present if (!empty($validated_data['hvac_ticket_data'])) { self::process_ticket_data($event_id, $validated_data['hvac_ticket_data']); } // Log the creation error_log("HVAC Event Created: Event ID {$event_id} by user " . get_current_user_id()); return $event_id; } /** * Validate and sanitize form data * * @param array $form_data Raw form data * @return array|WP_Error Sanitized data or error */ private static function validate_and_sanitize($form_data) { $sanitized = array(); $errors = array(); // Required fields if (empty($form_data['event_title'])) { $errors[] = 'Event title is required'; } else { $sanitized['event_title'] = sanitize_text_field($form_data['event_title']); if (strlen($sanitized['event_title']) < 3) { $errors[] = 'Event title must be at least 3 characters'; } } // Event description (optional) if (!empty($form_data['event_description'])) { $sanitized['event_description'] = wp_kses_post($form_data['event_description']); } else { $sanitized['event_description'] = ''; } // Start datetime (required) if (empty($form_data['event_start_datetime'])) { $errors[] = 'Event start date and time is required'; } else { $sanitized['event_start_datetime'] = sanitize_text_field($form_data['event_start_datetime']); // Validate datetime format if (!self::validate_datetime($sanitized['event_start_datetime'])) { $errors[] = 'Invalid start date and time format'; } } // End datetime (optional, but validate if provided) if (!empty($form_data['event_end_datetime'])) { $sanitized['event_end_datetime'] = sanitize_text_field($form_data['event_end_datetime']); if (!self::validate_datetime($sanitized['event_end_datetime'])) { $errors[] = 'Invalid end date and time format'; } // Check that end is after start if (!empty($sanitized['event_start_datetime']) && strtotime($sanitized['event_end_datetime']) <= strtotime($sanitized['event_start_datetime'])) { $errors[] = 'End date and time must be after start date and time'; } } // Timezone if (!empty($form_data['event_timezone'])) { $sanitized['event_timezone'] = sanitize_text_field($form_data['event_timezone']); } // Capacity if (!empty($form_data['event_capacity'])) { $capacity = absint($form_data['event_capacity']); if ($capacity < 1 || $capacity > 10000) { $errors[] = 'Event capacity must be between 1 and 10,000'; } else { $sanitized['event_capacity'] = $capacity; } } // Cost if (!empty($form_data['event_cost'])) { $cost = floatval($form_data['event_cost']); if ($cost < 0) { $errors[] = 'Event cost cannot be negative'; } else { $sanitized['event_cost'] = $cost; } } // Featured image if (!empty($form_data['event_featured_image'])) { $sanitized['event_featured_image'] = absint($form_data['event_featured_image']); } // Venue IDs if (!empty($form_data['venue_ids'])) { $sanitized['venue_ids'] = is_array($form_data['venue_ids']) ? array_map('absint', $form_data['venue_ids']) : array(absint($form_data['venue_ids'])); } // Organizer IDs if (!empty($form_data['organizer_ids'])) { $sanitized['organizer_ids'] = is_array($form_data['organizer_ids']) ? array_map('absint', $form_data['organizer_ids']) : array(absint($form_data['organizer_ids'])); } // Category IDs if (!empty($form_data['category_ids'])) { $sanitized['category_ids'] = is_array($form_data['category_ids']) ? array_map('absint', $form_data['category_ids']) : array(absint($form_data['category_ids'])); } // Ticket data if (!empty($form_data['hvac_ticket_data'])) { $ticket_data = json_decode(stripslashes($form_data['hvac_ticket_data']), true); if (json_last_error() === JSON_ERROR_NONE) { $sanitized['hvac_ticket_data'] = $ticket_data; } } if (!empty($errors)) { return new WP_Error('validation_failed', implode('. ', $errors)); } return $sanitized; } /** * Validate datetime format * * @param string $datetime * @return bool */ private static function validate_datetime($datetime) { $parsed = date_parse($datetime); return $parsed['error_count'] === 0 && $parsed['warning_count'] === 0; } /** * Convert datetime format for TEC compatibility * * @param string $datetime * @return string */ private static function convert_datetime_for_tec($datetime) { // Convert to UTC timestamp and then to TEC format $timestamp = strtotime($datetime); return date('Y-m-d H:i:s', $timestamp); } /** * Validate user permissions for updating an event * * @param int $event_id The event ID * @param int $user_id The user ID * @return bool True if user can edit, false otherwise */ public static function validate_update_permissions($event_id, $user_id) { // Check if user is logged in if (!$user_id) { return false; } // Get the event post $event = get_post($event_id); if (!$event || $event->post_type !== 'tribe_events') { return false; } $user = get_userdata($user_id); if (!$user) { return false; } // Check if user is the event author if ($event->post_author == $user_id) { return true; } // Check if user has master trainer role if (in_array('hvac_master_trainer', $user->roles)) { return true; } // Check if user has admin capabilities if (user_can($user_id, 'manage_options')) { return true; } return false; } /** * Get event data for editing * * @param int $event_id The event ID * @return array|WP_Error Event data or error */ public static function get_event_data_for_editing($event_id) { // Validate permissions if (!self::validate_update_permissions($event_id, get_current_user_id())) { return new WP_Error('permission_denied', 'You do not have permission to edit this event'); } $event = get_post($event_id); if (!$event || $event->post_type !== 'tribe_events') { return new WP_Error('event_not_found', 'Event not found'); } // Get event meta data $meta = get_post_meta($event_id); // Get venue information $venue_id = get_post_meta($event_id, '_EventVenueID', true); $venue_ids = $venue_id ? array($venue_id) : array(); // Get organizer information $organizer_ids = get_post_meta($event_id, '_EventOrganizerID', true); if (!is_array($organizer_ids)) { $organizer_ids = $organizer_ids ? array($organizer_ids) : array(); } // Get categories $categories = wp_get_object_terms($event_id, 'tribe_events_cat', array('fields' => 'ids')); $category_ids = is_array($categories) ? $categories : array(); // Get featured image $featured_image_id = get_post_thumbnail_id($event_id); // Get ticket data $ticket_data = get_post_meta($event_id, '_hvac_ticket_data', true); return array( 'event_title' => $event->post_title, 'event_description' => $event->post_content, 'event_start_datetime' => get_post_meta($event_id, '_EventStartDate', true), 'event_end_datetime' => get_post_meta($event_id, '_EventEndDate', true), 'event_timezone' => get_post_meta($event_id, '_EventTimezone', true), 'event_capacity' => get_post_meta($event_id, '_EventCapacity', true), 'event_cost' => get_post_meta($event_id, '_EventCost', true), 'event_featured_image' => $featured_image_id, 'venue_ids' => $venue_ids, 'organizer_ids' => $organizer_ids, 'category_ids' => $category_ids, 'hvac_ticket_data' => $ticket_data, 'post_status' => $event->post_status, 'post_author' => $event->post_author ); } /** * Validate and sanitize form data for updates * * @param array $form_data Raw form data * @param int $event_id Event ID being updated * @return array|WP_Error Sanitized data or error */ private static function validate_and_sanitize_update($form_data, $event_id) { $sanitized = array(); $errors = array(); // Get existing event data for comparison $existing_data = self::get_event_data_for_editing($event_id); if (is_wp_error($existing_data)) { return $existing_data; } // Required fields if (empty($form_data['event_title'])) { $errors[] = 'Event title is required'; } else { $sanitized['event_title'] = sanitize_text_field($form_data['event_title']); if (strlen($sanitized['event_title']) < 3) { $errors[] = 'Event title must be at least 3 characters'; } } // Event description (optional) if (isset($form_data['event_description'])) { $sanitized['event_description'] = wp_kses_post($form_data['event_description']); } else { $sanitized['event_description'] = ''; } // Start datetime (required) if (empty($form_data['event_start_datetime'])) { $errors[] = 'Event start date and time is required'; } else { $sanitized['event_start_datetime'] = sanitize_text_field($form_data['event_start_datetime']); // Validate datetime format if (!self::validate_datetime($sanitized['event_start_datetime'])) { $errors[] = 'Invalid start date and time format'; } } // End datetime (optional, but validate if provided) if (!empty($form_data['event_end_datetime'])) { $sanitized['event_end_datetime'] = sanitize_text_field($form_data['event_end_datetime']); if (!self::validate_datetime($sanitized['event_end_datetime'])) { $errors[] = 'Invalid end date and time format'; } // Check that end is after start if (!empty($sanitized['event_start_datetime']) && strtotime($sanitized['event_end_datetime']) <= strtotime($sanitized['event_start_datetime'])) { $errors[] = 'End date and time must be after start date and time'; } } // Timezone if (isset($form_data['event_timezone'])) { $sanitized['event_timezone'] = sanitize_text_field($form_data['event_timezone']); } // Capacity if (isset($form_data['event_capacity'])) { if (!empty($form_data['event_capacity'])) { $capacity = absint($form_data['event_capacity']); if ($capacity < 1 || $capacity > 10000) { $errors[] = 'Event capacity must be between 1 and 10,000'; } else { $sanitized['event_capacity'] = $capacity; } } else { $sanitized['event_capacity'] = ''; } } // Cost if (isset($form_data['event_cost'])) { if (!empty($form_data['event_cost'])) { $cost = floatval($form_data['event_cost']); if ($cost < 0) { $errors[] = 'Event cost cannot be negative'; } else { $sanitized['event_cost'] = $cost; } } else { $sanitized['event_cost'] = ''; } } // Featured image if (isset($form_data['event_featured_image'])) { $sanitized['event_featured_image'] = absint($form_data['event_featured_image']); } // Venue IDs if (isset($form_data['venue_ids'])) { $sanitized['venue_ids'] = is_array($form_data['venue_ids']) ? array_map('absint', $form_data['venue_ids']) : array(absint($form_data['venue_ids'])); } // Organizer IDs if (isset($form_data['organizer_ids'])) { $sanitized['organizer_ids'] = is_array($form_data['organizer_ids']) ? array_map('absint', $form_data['organizer_ids']) : array(absint($form_data['organizer_ids'])); } // Category IDs if (isset($form_data['category_ids'])) { $sanitized['category_ids'] = is_array($form_data['category_ids']) ? array_map('absint', $form_data['category_ids']) : array(absint($form_data['category_ids'])); } // Ticket data if (isset($form_data['hvac_ticket_data'])) { if (!empty($form_data['hvac_ticket_data'])) { $ticket_data = json_decode(stripslashes($form_data['hvac_ticket_data']), true); if (json_last_error() === JSON_ERROR_NONE) { $sanitized['hvac_ticket_data'] = $ticket_data; } } else { $sanitized['hvac_ticket_data'] = ''; } } if (!empty($errors)) { return new WP_Error('validation_failed', implode('. ', $errors)); } return $sanitized; } /** * Process ticket data for the event * * @param int $event_id * @param array $ticket_data */ private static function process_ticket_data($event_id, $ticket_data) { // This would integrate with TEC tickets or custom ticketing system // For now, just store as meta data if (!empty($ticket_data) && is_array($ticket_data)) { update_post_meta($event_id, '_hvac_ticket_data', $ticket_data); } } }