upskill-event-manager/includes/class-hvac-trainer-profile-manager.php
bengizmo e4f079a89c feat: Major registration refactor and new trainer management pages
- Refactored registration form:
  * Moved Application Details to Personal Information section
  * Renamed Business Information to Training Organization Information
  * Added required Organization Logo upload with media library integration
  * Added Headquarters location fields (City, State/Province, Country)
  * Moved training-related fields into Organization section
  * Created conditional Training Venue Information section with auto-population

- Created comprehensive venue management system:
  * Training Venues List page (/trainer/venue/list) with filtering and pagination
  * Manage Venue page (/trainer/venue/manage) for create/edit operations
  * Full integration with The Events Calendar venue post type
  * AJAX-powered forms with real-time validation

- Created trainer profile system:
  * Trainer Profile view page (/trainer/profile) with stats and certifications
  * Profile Edit page (/trainer/profile/edit) with photo upload
  * Years of experience tracking and professional information
  * Integration with user meta and custom fields

- Created training organizers management:
  * Organizers List page (/trainer/organizer/list) with search functionality
  * Manage Organizer page (/trainer/organizer/manage) for CRUD operations
  * Organization logo upload and headquarters tracking
  * Full integration with The Events Calendar organizer post type

- Technical improvements:
  * Modular PHP class architecture for each feature
  * Comprehensive AJAX handlers with security nonces
  * Responsive CSS design for all new pages
  * JavaScript form validation and dynamic behavior
  * Proper WordPress and TEC API integration

All new features follow hierarchical URL structure and include breadcrumb navigation.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-30 16:29:51 -03:00

537 lines
No EOL
24 KiB
PHP

<?php
/**
* HVAC Trainer Profile Manager
*
* @package HVAC_Community_Events
* @since 2.0.0
*/
if (!defined('ABSPATH')) {
exit;
}
/**
* HVAC_Trainer_Profile_Manager class
*/
class HVAC_Trainer_Profile_Manager {
/**
* Constructor
*/
public function __construct() {
// Register shortcodes
add_shortcode('hvac_trainer_profile_view', array($this, 'render_profile_view'));
add_shortcode('hvac_trainer_profile_edit', array($this, 'render_profile_edit'));
// Enqueue scripts
add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts'));
// Handle AJAX requests
add_action('wp_ajax_hvac_update_profile', array($this, 'ajax_update_profile'));
add_action('wp_ajax_hvac_upload_profile_photo', array($this, 'ajax_upload_profile_photo'));
}
/**
* Enqueue scripts and styles
*/
public function enqueue_scripts() {
if (is_page('trainer/profile') || is_page('trainer/profile/edit')) {
wp_enqueue_style(
'hvac-trainer-profile-style',
HVAC_PLUGIN_URL . 'assets/css/hvac-trainer-profile.css',
array(),
HVAC_PLUGIN_VERSION
);
wp_enqueue_script(
'hvac-trainer-profile-js',
HVAC_PLUGIN_URL . 'assets/js/hvac-trainer-profile.js',
array('jquery'),
HVAC_PLUGIN_VERSION,
true
);
wp_localize_script('hvac-trainer-profile-js', 'hvacProfile', array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('hvac_profile_nonce')
));
// Enqueue media uploader for profile photo
if (is_page('trainer/profile/edit')) {
wp_enqueue_media();
}
}
}
/**
* Render profile view
*/
public function render_profile_view() {
if (!is_user_logged_in() || !current_user_can('hvac_trainer')) {
return '<p>You must be logged in as a trainer to view this page.</p>';
}
$user_id = get_current_user_id();
$user = get_userdata($user_id);
// Get user meta
$phone = get_user_meta($user_id, 'user_phone', true);
$city = get_user_meta($user_id, 'user_city', true);
$state = get_user_meta($user_id, 'user_state', true);
$country = get_user_meta($user_id, 'user_country', true);
$linkedin = get_user_meta($user_id, 'user_linkedin', true);
$certifications = get_user_meta($user_id, 'trainer_certifications', true);
$years_experience = get_user_meta($user_id, 'years_experience', true);
$profile_photo_id = get_user_meta($user_id, 'profile_photo_id', true);
// Get organization info
$organizer_id = get_user_meta($user_id, 'organizer_id', true);
$organization = null;
if ($organizer_id) {
$organization = get_post($organizer_id);
}
ob_start();
?>
<div class="hvac-trainer-profile-view">
<div class="hvac-page-header">
<h1>Trainer Profile</h1>
<a href="/trainer/profile/edit/" class="hvac-button hvac-button-primary">Edit Profile</a>
</div>
<div class="hvac-breadcrumb">
<a href="/trainer/dashboard/">Trainer</a> &gt; <a href="/trainer/profile/">Profile</a> &gt; View
</div>
<div class="hvac-profile-content">
<div class="hvac-profile-sidebar">
<div class="hvac-profile-photo">
<?php if ($profile_photo_id): ?>
<?php echo wp_get_attachment_image($profile_photo_id, 'medium', false, array('alt' => $user->display_name)); ?>
<?php else: ?>
<div class="hvac-profile-photo-placeholder">
<span><?php echo esc_html(substr($user->first_name, 0, 1) . substr($user->last_name, 0, 1)); ?></span>
</div>
<?php endif; ?>
</div>
<div class="hvac-profile-stats">
<div class="hvac-stat-item">
<span class="hvac-stat-value"><?php echo $this->get_trainer_event_count($user_id); ?></span>
<span class="hvac-stat-label">Events Created</span>
</div>
<div class="hvac-stat-item">
<span class="hvac-stat-value"><?php echo $this->get_trainer_student_count($user_id); ?></span>
<span class="hvac-stat-label">Students Trained</span>
</div>
<?php if ($years_experience): ?>
<div class="hvac-stat-item">
<span class="hvac-stat-value"><?php echo esc_html($years_experience); ?></span>
<span class="hvac-stat-label">Years Experience</span>
</div>
<?php endif; ?>
</div>
</div>
<div class="hvac-profile-main">
<div class="hvac-profile-section">
<h2>Personal Information</h2>
<div class="hvac-profile-details">
<div class="hvac-detail-row">
<span class="hvac-detail-label">Name:</span>
<span class="hvac-detail-value"><?php echo esc_html($user->first_name . ' ' . $user->last_name); ?></span>
</div>
<div class="hvac-detail-row">
<span class="hvac-detail-label">Email:</span>
<span class="hvac-detail-value"><?php echo esc_html($user->user_email); ?></span>
</div>
<?php if ($phone): ?>
<div class="hvac-detail-row">
<span class="hvac-detail-label">Phone:</span>
<span class="hvac-detail-value"><?php echo esc_html($phone); ?></span>
</div>
<?php endif; ?>
<div class="hvac-detail-row">
<span class="hvac-detail-label">Location:</span>
<span class="hvac-detail-value">
<?php
$location_parts = array_filter(array($city, $state, $country));
echo esc_html(implode(', ', $location_parts));
?>
</span>
</div>
<?php if ($linkedin): ?>
<div class="hvac-detail-row">
<span class="hvac-detail-label">LinkedIn:</span>
<span class="hvac-detail-value">
<a href="<?php echo esc_url($linkedin); ?>" target="_blank">View Profile</a>
</span>
</div>
<?php endif; ?>
</div>
</div>
<?php if (!empty($user->description)): ?>
<div class="hvac-profile-section">
<h2>About</h2>
<div class="hvac-profile-bio">
<?php echo wp_kses_post(wpautop($user->description)); ?>
</div>
</div>
<?php endif; ?>
<?php if ($organization): ?>
<div class="hvac-profile-section">
<h2>Training Organization</h2>
<div class="hvac-profile-details">
<div class="hvac-detail-row">
<span class="hvac-detail-label">Organization:</span>
<span class="hvac-detail-value"><?php echo esc_html($organization->post_title); ?></span>
</div>
<?php
$org_city = get_post_meta($organizer_id, '_hvac_headquarters_city', true);
$org_state = get_post_meta($organizer_id, '_hvac_headquarters_state', true);
$org_country = get_post_meta($organizer_id, '_hvac_headquarters_country', true);
if ($org_city || $org_state || $org_country):
?>
<div class="hvac-detail-row">
<span class="hvac-detail-label">Headquarters:</span>
<span class="hvac-detail-value">
<?php
$hq_parts = array_filter(array($org_city, $org_state, $org_country));
echo esc_html(implode(', ', $hq_parts));
?>
</span>
</div>
<?php endif; ?>
</div>
</div>
<?php endif; ?>
<?php if ($certifications): ?>
<div class="hvac-profile-section">
<h2>Certifications</h2>
<div class="hvac-certifications-list">
<?php
$cert_array = is_array($certifications) ? $certifications : explode("\n", $certifications);
foreach ($cert_array as $cert):
if (trim($cert)):
?>
<div class="hvac-certification-item">
<i class="dashicons dashicons-awards"></i>
<?php echo esc_html(trim($cert)); ?>
</div>
<?php
endif;
endforeach;
?>
</div>
</div>
<?php endif; ?>
</div>
</div>
</div>
<?php
return ob_get_clean();
}
/**
* Render profile edit form
*/
public function render_profile_edit() {
if (!is_user_logged_in() || !current_user_can('hvac_trainer')) {
return '<p>You must be logged in as a trainer to view this page.</p>';
}
$user_id = get_current_user_id();
$user = get_userdata($user_id);
// Get user meta
$phone = get_user_meta($user_id, 'user_phone', true);
$city = get_user_meta($user_id, 'user_city', true);
$state = get_user_meta($user_id, 'user_state', true);
$country = get_user_meta($user_id, 'user_country', true);
$linkedin = get_user_meta($user_id, 'user_linkedin', true);
$website = $user->user_url;
$certifications = get_user_meta($user_id, 'trainer_certifications', true);
$years_experience = get_user_meta($user_id, 'years_experience', true);
$profile_photo_id = get_user_meta($user_id, 'profile_photo_id', true);
ob_start();
?>
<div class="hvac-trainer-profile-edit">
<div class="hvac-page-header">
<h1>Edit Profile</h1>
</div>
<div class="hvac-breadcrumb">
<a href="/trainer/dashboard/">Trainer</a> &gt; <a href="/trainer/profile/">Profile</a> &gt; Edit
</div>
<form id="hvac-profile-form" class="hvac-form">
<?php wp_nonce_field('hvac_profile_edit', 'hvac_profile_nonce'); ?>
<div class="hvac-form-section">
<h3>Profile Photo</h3>
<div class="hvac-profile-photo-upload">
<div class="hvac-current-photo">
<?php if ($profile_photo_id): ?>
<?php echo wp_get_attachment_image($profile_photo_id, 'thumbnail'); ?>
<?php else: ?>
<div class="hvac-photo-placeholder">No photo uploaded</div>
<?php endif; ?>
</div>
<div class="hvac-photo-actions">
<button type="button" id="hvac-upload-photo" class="hvac-button hvac-button-secondary">
<?php echo $profile_photo_id ? 'Change Photo' : 'Upload Photo'; ?>
</button>
<?php if ($profile_photo_id): ?>
<button type="button" id="hvac-remove-photo" class="hvac-button hvac-button-danger-outline">
Remove Photo
</button>
<?php endif; ?>
<input type="hidden" id="profile_photo_id" name="profile_photo_id" value="<?php echo $profile_photo_id; ?>" />
</div>
</div>
</div>
<div class="hvac-form-section">
<h3>Personal Information</h3>
<div class="hvac-form-row hvac-form-row-half">
<div>
<label for="first_name">First Name *</label>
<input type="text" id="first_name" name="first_name" required
value="<?php echo esc_attr($user->first_name); ?>" />
</div>
<div>
<label for="last_name">Last Name *</label>
<input type="text" id="last_name" name="last_name" required
value="<?php echo esc_attr($user->last_name); ?>" />
</div>
</div>
<div class="hvac-form-row">
<label for="display_name">Display Name *</label>
<input type="text" id="display_name" name="display_name" required
value="<?php echo esc_attr($user->display_name); ?>" />
</div>
<div class="hvac-form-row">
<label for="email">Email Address *</label>
<input type="email" id="email" name="email" required
value="<?php echo esc_attr($user->user_email); ?>" />
</div>
<div class="hvac-form-row">
<label for="phone">Phone Number</label>
<input type="tel" id="phone" name="phone"
value="<?php echo esc_attr($phone); ?>" />
</div>
<div class="hvac-form-row">
<label for="description">Bio / About</label>
<textarea id="description" name="description" rows="5"><?php echo esc_textarea($user->description); ?></textarea>
</div>
</div>
<div class="hvac-form-section">
<h3>Location</h3>
<div class="hvac-form-row">
<label for="city">City</label>
<input type="text" id="city" name="city"
value="<?php echo esc_attr($city); ?>" />
</div>
<div class="hvac-form-row hvac-form-row-half">
<div>
<label for="state">State/Province</label>
<input type="text" id="state" name="state"
value="<?php echo esc_attr($state); ?>" />
</div>
<div>
<label for="country">Country</label>
<select id="country" name="country">
<option value="">Select Country</option>
<?php
$countries = array(
'United States' => 'United States',
'Canada' => 'Canada',
'United Kingdom' => 'United Kingdom',
'Australia' => 'Australia'
);
foreach ($countries as $code => $name) {
printf(
'<option value="%s" %s>%s</option>',
esc_attr($code),
selected($country, $code, false),
esc_html($name)
);
}
?>
</select>
</div>
</div>
</div>
<div class="hvac-form-section">
<h3>Professional Information</h3>
<div class="hvac-form-row">
<label for="years_experience">Years of Experience</label>
<input type="number" id="years_experience" name="years_experience" min="0" max="50"
value="<?php echo esc_attr($years_experience); ?>" />
</div>
<div class="hvac-form-row">
<label for="certifications">Certifications (one per line)</label>
<textarea id="certifications" name="certifications" rows="5"><?php echo esc_textarea($certifications); ?></textarea>
</div>
<div class="hvac-form-row">
<label for="website">Website</label>
<input type="url" id="website" name="website"
value="<?php echo esc_attr($website); ?>" />
</div>
<div class="hvac-form-row">
<label for="linkedin">LinkedIn Profile</label>
<input type="url" id="linkedin" name="linkedin"
value="<?php echo esc_attr($linkedin); ?>" />
</div>
</div>
<div class="hvac-form-actions">
<button type="submit" class="hvac-button hvac-button-primary">Save Changes</button>
<a href="/trainer/profile/" class="hvac-button hvac-button-secondary">Cancel</a>
</div>
</form>
</div>
<?php
return ob_get_clean();
}
/**
* AJAX handler for updating profile
*/
public function ajax_update_profile() {
check_ajax_referer('hvac_profile_nonce', 'nonce');
if (!current_user_can('hvac_trainer')) {
wp_send_json_error('Unauthorized');
}
$user_id = get_current_user_id();
// Update user data
$user_data = array(
'ID' => $user_id,
'first_name' => sanitize_text_field($_POST['first_name']),
'last_name' => sanitize_text_field($_POST['last_name']),
'display_name' => sanitize_text_field($_POST['display_name']),
'user_email' => sanitize_email($_POST['email']),
'user_url' => esc_url_raw($_POST['website']),
'description' => wp_kses_post($_POST['description'])
);
$result = wp_update_user($user_data);
if (is_wp_error($result)) {
wp_send_json_error($result->get_error_message());
}
// Update user meta
update_user_meta($user_id, 'user_phone', sanitize_text_field($_POST['phone']));
update_user_meta($user_id, 'user_city', sanitize_text_field($_POST['city']));
update_user_meta($user_id, 'user_state', sanitize_text_field($_POST['state']));
update_user_meta($user_id, 'user_country', sanitize_text_field($_POST['country']));
update_user_meta($user_id, 'user_linkedin', esc_url_raw($_POST['linkedin']));
update_user_meta($user_id, 'years_experience', intval($_POST['years_experience']));
update_user_meta($user_id, 'trainer_certifications', sanitize_textarea_field($_POST['certifications']));
// Update profile photo if changed
if (isset($_POST['profile_photo_id'])) {
update_user_meta($user_id, 'profile_photo_id', intval($_POST['profile_photo_id']));
}
wp_send_json_success('Profile updated successfully.');
}
/**
* AJAX handler for uploading profile photo
*/
public function ajax_upload_profile_photo() {
check_ajax_referer('hvac_profile_nonce', 'nonce');
if (!current_user_can('hvac_trainer')) {
wp_send_json_error('Unauthorized');
}
if (!isset($_FILES['profile_photo'])) {
wp_send_json_error('No file uploaded');
}
require_once(ABSPATH . 'wp-admin/includes/image.php');
require_once(ABSPATH . 'wp-admin/includes/file.php');
require_once(ABSPATH . 'wp-admin/includes/media.php');
$attachment_id = media_handle_upload('profile_photo', 0);
if (is_wp_error($attachment_id)) {
wp_send_json_error($attachment_id->get_error_message());
}
// Update user meta
update_user_meta(get_current_user_id(), 'profile_photo_id', $attachment_id);
wp_send_json_success(array(
'attachment_id' => $attachment_id,
'url' => wp_get_attachment_image_url($attachment_id, 'thumbnail')
));
}
/**
* Get trainer event count
*/
private function get_trainer_event_count($user_id) {
$post_type = class_exists('Tribe__Events__Main') ? Tribe__Events__Main::POSTTYPE : 'tribe_events';
$count = count_user_posts($user_id, $post_type);
return $count;
}
/**
* Get trainer student count
*/
private function get_trainer_student_count($user_id) {
global $wpdb;
// Get all events by this trainer
$post_type = class_exists('Tribe__Events__Main') ? Tribe__Events__Main::POSTTYPE : 'tribe_events';
$events = get_posts(array(
'post_type' => $post_type,
'author' => $user_id,
'posts_per_page' => -1,
'fields' => 'ids'
));
if (empty($events)) {
return 0;
}
// Count attendees across all events
$attendee_count = 0;
foreach ($events as $event_id) {
$attendees = get_post_meta($event_id, '_tribe_tickets_attendees', true);
if (is_array($attendees)) {
$attendee_count += count($attendees);
}
}
return $attendee_count;
}
}