upskill-event-manager/includes/find-trainer/class-hvac-find-trainer-page.php
bengizmo 37f4180e1c feat: Add massive missing plugin infrastructure to repository
🚨 CRITICAL: Fixed deployment blockers by adding missing core directories:

**Community System (CRITICAL)**
- includes/community/ - Login_Handler and all community classes
- templates/community/ - Community login forms

**Certificate System (CRITICAL)**
- includes/certificates/ - 8+ certificate classes and handlers
- templates/certificates/ - Certificate reports and generation templates

**Core Individual Classes (CRITICAL)**
- includes/class-hvac-event-summary.php
- includes/class-hvac-trainer-profile-manager.php
- includes/class-hvac-master-dashboard-data.php
- Plus 40+ other individual HVAC classes

**Major Feature Systems (HIGH)**
- includes/database/ - Training leads database tables
- includes/find-trainer/ - Find trainer directory and MapGeo integration
- includes/google-sheets/ - Google Sheets integration system
- includes/zoho/ - Complete Zoho CRM integration
- includes/communication/ - Communication templates system

**Template Infrastructure**
- templates/attendee/, templates/email-attendees/
- templates/event-summary/, templates/status/
- templates/template-parts/ - Shared template components

**Impact:**
- 70+ files added covering 10+ missing directories
- Resolves ALL deployment blockers and feature breakdowns
- Plugin activation should now work correctly
- Multi-machine deployment fully supported

🔧 Generated with Claude Code

Co-Authored-By: Ben Reed <ben@tealmaker.com>
2025-08-11 13:30:11 -03:00

570 lines
No EOL
20 KiB
PHP

<?php
/**
* Find a Trainer Page Handler
*
* @package HVAC_Plugin
* @since 1.0.0
*/
if (!defined('ABSPATH')) {
exit;
}
/**
* Class HVAC_Find_Trainer_Page
* Manages the Find a Trainer page functionality
*/
class HVAC_Find_Trainer_Page {
/**
* Instance of this class
*
* @var HVAC_Find_Trainer_Page
*/
private static $instance = null;
/**
* Page slug
*
* @var string
*/
private $page_slug = 'find-a-trainer';
/**
* Get instance of this class
*
* @return HVAC_Find_Trainer_Page
*/
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor
*/
private function __construct() {
$this->init_hooks();
}
/**
* Initialize hooks
*/
private function init_hooks() {
add_action('init', [$this, 'register_page']);
add_action('wp_enqueue_scripts', [$this, 'enqueue_assets']);
add_filter('body_class', [$this, 'add_body_classes']);
add_shortcode('hvac_find_trainer', [$this, 'render_shortcode']);
add_shortcode('hvac_trainer_directory', [$this, 'render_directory_shortcode']);
// AJAX handlers
add_action('wp_ajax_hvac_get_trainer_upcoming_events', [$this, 'ajax_get_upcoming_events']);
add_action('wp_ajax_nopriv_hvac_get_trainer_upcoming_events', [$this, 'ajax_get_upcoming_events']);
}
/**
* Register the Find a Trainer page
*/
public function register_page() {
// Check if page exists
$page = get_page_by_path($this->page_slug);
if (!$page) {
$this->create_page();
}
}
/**
* Create the Find a Trainer page
*/
private function create_page() {
$page_content = $this->get_page_content();
$page_data = [
'post_title' => 'Find a Trainer',
'post_name' => $this->page_slug,
'post_content' => $page_content,
'post_status' => 'publish',
'post_type' => 'page',
'post_author' => 1,
'meta_input' => [
'_wp_page_template' => 'default',
'ast-site-content-layout' => 'page-builder',
'site-post-title' => 'disabled',
'site-sidebar-layout' => 'no-sidebar',
'ast-main-header-display' => 'enabled',
'ast-hfb-above-header-display' => 'disabled',
'ast-hfb-below-header-display' => 'disabled',
'ast-featured-img' => 'disabled'
]
];
$page_id = wp_insert_post($page_data);
if ($page_id && !is_wp_error($page_id)) {
update_option('hvac_find_trainer_page_id', $page_id);
}
}
/**
* Get the page content with Gutenberg blocks
*/
private function get_page_content() {
return '<!-- wp:group {"className":"hvac-find-trainer-wrapper ast-container"} -->
<div class="wp-block-group hvac-find-trainer-wrapper ast-container">
<!-- wp:group {"className":"hvac-find-trainer-intro"} -->
<div class="wp-block-group hvac-find-trainer-intro">
<!-- wp:paragraph -->
<p>Find certified HVAC trainers in your area. Use the interactive map and filters below to discover trainers who match your specific needs. Click on any trainer to view their profile and contact them directly.</p>
<!-- /wp:paragraph -->
</div>
<!-- /wp:group -->
<!-- wp:columns {"className":"hvac-map-filter-section"} -->
<div class="wp-block-columns hvac-map-filter-section">
<!-- wp:column {"width":"66.66%","className":"hvac-map-container"} -->
<div class="wp-block-column hvac-map-container" style="flex-basis:66.66%">
<!-- wp:shortcode -->
[display-map id="5872"]
<!-- /wp:shortcode -->
</div>
<!-- /wp:column -->
<!-- wp:column {"width":"33.33%","className":"hvac-filter-sidebar"} -->
<div class="wp-block-column hvac-filter-sidebar" style="flex-basis:33.33%">
<!-- wp:html -->
<div class="hvac-filter-controls">
<input type="text" class="hvac-search-input" placeholder="Search trainers..." aria-label="Search trainers">
<div class="hvac-filter-label">Filters:</div>
<button class="hvac-filter-button" data-filter="state" aria-label="Filter by State or Province">
<span class="hvac-filter-icon">▼</span> State / Province
</button>
<button class="hvac-filter-button" data-filter="business_type" aria-label="Filter by Business Type">
<span class="hvac-filter-icon">▼</span> Business Type
</button>
<button class="hvac-filter-button" data-filter="training_format" aria-label="Filter by Training Format">
<span class="hvac-filter-icon">▼</span> Training Format
</button>
<button class="hvac-filter-button" data-filter="training_resources" aria-label="Filter by Training Resources">
<span class="hvac-filter-icon">▼</span> Training Resources
</button>
<div class="hvac-active-filters"></div>
</div>
<!-- /wp:html -->
</div>
<!-- /wp:column -->
</div>
<!-- /wp:columns -->
<!-- wp:shortcode -->
[hvac_trainer_directory]
<!-- /wp:shortcode -->
<!-- wp:group {"className":"hvac-trainer-cta"} -->
<div class="wp-block-group hvac-trainer-cta">
<!-- wp:paragraph -->
<p>Are you an HVAC Trainer that wants to be listed in our directory?</p>
<!-- /wp:paragraph -->
<!-- wp:buttons -->
<div class="wp-block-buttons">
<!-- wp:button {"className":"hvac-become-trainer-btn"} -->
<div class="wp-block-button hvac-become-trainer-btn">
<a class="wp-block-button__link" href="/trainer-registration/">Become a Trainer</a>
</div>
<!-- /wp:button -->
</div>
<!-- /wp:buttons -->
</div>
<!-- /wp:group -->
</div>
<!-- /wp:group -->';
}
/**
* Enqueue assets for the Find a Trainer page
*/
public function enqueue_assets() {
if (!$this->is_find_trainer_page()) {
return;
}
// Enqueue CSS
wp_enqueue_style(
'hvac-find-trainer',
HVAC_PLUGIN_URL . 'assets/css/find-trainer.css',
['astra-theme-css'],
HVAC_VERSION
);
// Enqueue JavaScript
wp_enqueue_script(
'hvac-find-trainer',
HVAC_PLUGIN_URL . 'assets/js/find-trainer.js',
['jquery'],
HVAC_VERSION,
true
);
// Localize script
wp_localize_script('hvac-find-trainer', 'hvac_find_trainer', [
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('hvac_find_trainer'),
'map_id' => '5872',
'messages' => [
'loading' => __('Loading...', 'hvac'),
'error' => __('An error occurred. Please try again.', 'hvac'),
'no_results' => __('No trainers found matching your criteria.', 'hvac'),
'form_error' => __('Please check the form and try again.', 'hvac'),
'form_success' => __('Your message has been sent! Check your inbox for more details.', 'hvac')
]
]);
}
/**
* Add body classes for the Find a Trainer page
*/
public function add_body_classes($classes) {
if ($this->is_find_trainer_page()) {
$classes[] = 'hvac-find-trainer-page';
$classes[] = 'hvac-full-width';
}
return $classes;
}
/**
* Check if current page is the Find a Trainer page
*/
private function is_find_trainer_page() {
return is_page($this->page_slug) || is_page(get_option('hvac_find_trainer_page_id'));
}
/**
* Render the main shortcode
*/
public function render_shortcode($atts) {
$atts = shortcode_atts([
'show_map' => true,
'show_filters' => true,
'show_directory' => true
], $atts);
ob_start();
?>
<div class="hvac-find-trainer-container">
<?php if ($atts['show_map']) : ?>
<div class="hvac-map-section">
<?php echo do_shortcode('[display-map id="5872"]'); ?>
</div>
<?php endif; ?>
<?php if ($atts['show_filters']) : ?>
<div class="hvac-filter-section">
<?php $this->render_filters(); ?>
</div>
<?php endif; ?>
<?php if ($atts['show_directory']) : ?>
<div class="hvac-directory-section">
<?php $this->render_directory(); ?>
</div>
<?php endif; ?>
</div>
<?php
return ob_get_clean();
}
/**
* Render the trainer directory shortcode
*/
public function render_directory_shortcode($atts) {
$atts = shortcode_atts([
'per_page' => 12,
'columns' => 2
], $atts);
ob_start();
$this->render_directory($atts);
return ob_get_clean();
}
/**
* Render filter controls
*/
private function render_filters() {
?>
<div class="hvac-filter-controls">
<input type="text" class="hvac-search-input" placeholder="Search trainers..." aria-label="Search trainers">
<div class="hvac-filter-label">Filters:</div>
<button class="hvac-filter-button" data-filter="state">
<span class="hvac-filter-icon">▼</span> State / Province
</button>
<button class="hvac-filter-button" data-filter="business_type">
<span class="hvac-filter-icon">▼</span> Business Type
</button>
<button class="hvac-filter-button" data-filter="training_format">
<span class="hvac-filter-icon">▼</span> Training Format
</button>
<button class="hvac-filter-button" data-filter="training_resources">
<span class="hvac-filter-icon">▼</span> Training Resources
</button>
<div class="hvac-active-filters"></div>
</div>
<?php
}
/**
* Render trainer directory
*/
private function render_directory($args = []) {
$defaults = [
'per_page' => 12,
'columns' => 2
];
$args = wp_parse_args($args, $defaults);
// Get trainers
$query_args = [
'post_type' => 'trainer_profile',
'posts_per_page' => $args['per_page'],
'post_status' => 'publish',
'meta_query' => [
[
'key' => 'is_public_profile',
'value' => '1',
'compare' => '='
]
]
];
$trainers = new WP_Query($query_args);
?>
<div class="hvac-trainer-directory" data-columns="<?php echo esc_attr($args['columns']); ?>">
<div class="hvac-trainer-grid">
<?php if ($trainers->have_posts()) : ?>
<?php while ($trainers->have_posts()) : $trainers->the_post(); ?>
<?php $this->render_trainer_card(get_the_ID()); ?>
<?php endwhile; ?>
<?php else : ?>
<div class="hvac-no-results">
<p><?php _e('No trainers found. Please try adjusting your filters.', 'hvac'); ?></p>
</div>
<?php endif; ?>
</div>
<?php if ($trainers->max_num_pages > 1) : ?>
<div class="hvac-pagination">
<?php
echo paginate_links([
'total' => $trainers->max_num_pages,
'current' => max(1, get_query_var('paged')),
'prev_text' => '&laquo; Previous',
'next_text' => 'Next &raquo;'
]);
?>
</div>
<?php endif; ?>
</div>
<?php
wp_reset_postdata();
}
/**
* Render a trainer card
*/
private function render_trainer_card($profile_id) {
$user_id = get_post_meta($profile_id, 'user_id', true);
$trainer_name = get_post_meta($profile_id, 'trainer_display_name', true);
$city = get_post_meta($profile_id, 'trainer_city', true);
$state = get_post_meta($profile_id, 'trainer_state', true);
$certification = get_post_meta($profile_id, 'certification_type', true);
$profile_image = get_post_meta($profile_id, 'profile_image_url', true);
?>
<div class="hvac-trainer-card" data-profile-id="<?php echo esc_attr($profile_id); ?>">
<div class="hvac-trainer-card-inner">
<div class="hvac-trainer-avatar">
<?php if ($profile_image) : ?>
<img src="<?php echo esc_url($profile_image); ?>" alt="<?php echo esc_attr($trainer_name); ?>">
<?php else : ?>
<div class="hvac-default-avatar">
<span><?php echo esc_html(substr($trainer_name, 0, 1)); ?></span>
</div>
<?php endif; ?>
</div>
<div class="hvac-trainer-info">
<h3 class="trainer-name">
<a href="#" class="hvac-view-profile" data-profile-id="<?php echo esc_attr($profile_id); ?>">
<?php echo esc_html($trainer_name); ?>
</a>
</h3>
<p class="trainer-location">
<?php echo esc_html($city); ?>, <?php echo esc_html($state); ?>
</p>
<?php if ($certification) : ?>
<p class="trainer-certification">
<?php echo esc_html($certification); ?>
</p>
<?php endif; ?>
<div class="hvac-trainer-actions">
<button class="hvac-see-events" data-profile-id="<?php echo esc_attr($profile_id); ?>">
<span class="dashicons dashicons-calendar-alt"></span> See Events
</button>
</div>
</div>
</div>
</div>
<?php
}
/**
* Get map markers data for all trainers
*/
public function get_map_markers_data() {
$markers = [];
$args = [
'post_type' => 'trainer_profile',
'posts_per_page' => -1,
'post_status' => 'publish',
'meta_query' => [
[
'key' => 'is_public_profile',
'value' => '1',
'compare' => '='
],
[
'key' => 'latitude',
'compare' => 'EXISTS'
],
[
'key' => 'longitude',
'compare' => 'EXISTS'
]
]
];
$trainers = new WP_Query($args);
if ($trainers->have_posts()) {
while ($trainers->have_posts()) {
$trainers->the_post();
$profile_id = get_the_ID();
$markers[] = $this->format_marker_data($profile_id);
}
}
wp_reset_postdata();
return $markers;
}
/**
* Format marker data for a trainer
*/
private function format_marker_data($profile_id) {
$user_id = get_post_meta($profile_id, 'user_id', true);
$trainer_name = get_post_meta($profile_id, 'trainer_display_name', true);
$city = get_post_meta($profile_id, 'trainer_city', true);
$state = get_post_meta($profile_id, 'trainer_state', true);
$lat = get_post_meta($profile_id, 'latitude', true);
$lng = get_post_meta($profile_id, 'longitude', true);
$certification = get_post_meta($profile_id, 'certification_type', true);
$business_types = wp_get_post_terms($profile_id, 'business_type', ['fields' => 'names']);
return [
'id' => $profile_id,
'title' => $trainer_name,
'lat' => floatval($lat),
'lng' => floatval($lng),
'content' => $this->generate_marker_content($profile_id),
'data' => [
'trainer_id' => $user_id,
'profile_id' => $profile_id,
'certification' => $certification,
'business_type' => $business_types,
'state' => $state,
'city' => $city
]
];
}
/**
* Generate marker popup content
*/
private function generate_marker_content($profile_id) {
$trainer_name = get_post_meta($profile_id, 'trainer_display_name', true);
$city = get_post_meta($profile_id, 'trainer_city', true);
$state = get_post_meta($profile_id, 'trainer_state', true);
return sprintf(
'<div class="hvac-marker-popup" data-profile-id="%d">
<h4>%s</h4>
<p>%s, %s</p>
<button class="hvac-view-profile" data-profile-id="%d">View Profile</button>
</div>',
$profile_id,
esc_html($trainer_name),
esc_html($city),
esc_html($state),
$profile_id
);
}
/**
* AJAX handler for getting trainer upcoming events
*/
public function ajax_get_upcoming_events() {
// Verify nonce
if (!wp_verify_nonce($_POST['nonce'], 'hvac_find_trainer')) {
wp_send_json_error('Invalid nonce');
}
$profile_id = intval($_POST['profile_id']);
if (!$profile_id) {
wp_send_json_error('Invalid profile ID');
}
// Get the user ID from the profile
$user_id = get_post_meta($profile_id, 'user_id', true);
if (!$user_id) {
wp_send_json_error('No user found for this profile');
}
$upcoming_events = [];
// Get upcoming events using the fixed query
if (function_exists('tribe_get_events')) {
$events = tribe_get_events([
'author' => $user_id,
'posts_per_page' => 5,
'ends_after' => 'now',
'orderby' => 'event_date',
'order' => 'ASC'
]);
foreach ($events as $event) {
$upcoming_events[] = [
'title' => $event->post_title,
'date' => tribe_get_start_date($event->ID, false, 'M j, Y'),
'url' => get_permalink($event->ID)
];
}
}
wp_send_json_success([
'events' => $upcoming_events,
'count' => count($upcoming_events)
]);
}
}