🚨 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>
732 lines
No EOL
26 KiB
PHP
732 lines
No EOL
26 KiB
PHP
<?php
|
|
/**
|
|
* Trainer Directory Query Handler
|
|
*
|
|
* @package HVAC_Plugin
|
|
* @since 1.0.0
|
|
*/
|
|
|
|
if (!defined('ABSPATH')) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Class HVAC_Trainer_Directory_Query
|
|
* Handles querying and filtering of trainer profiles
|
|
*/
|
|
class HVAC_Trainer_Directory_Query {
|
|
|
|
/**
|
|
* Instance of this class
|
|
*
|
|
* @var HVAC_Trainer_Directory_Query
|
|
*/
|
|
private static $instance = null;
|
|
|
|
/**
|
|
* Cache group for queries
|
|
*
|
|
* @var string
|
|
*/
|
|
private $cache_group = 'hvac_trainers';
|
|
|
|
/**
|
|
* Cache expiration time
|
|
*
|
|
* @var int
|
|
*/
|
|
private $cache_expiration = 3600; // 1 hour
|
|
|
|
/**
|
|
* Get instance of this class
|
|
*
|
|
* @return HVAC_Trainer_Directory_Query
|
|
*/
|
|
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() {
|
|
// AJAX handlers
|
|
add_action('wp_ajax_hvac_get_filtered_trainers', [$this, 'ajax_get_filtered_trainers']);
|
|
add_action('wp_ajax_nopriv_hvac_get_filtered_trainers', [$this, 'ajax_get_filtered_trainers']);
|
|
|
|
add_action('wp_ajax_hvac_get_filter_options', [$this, 'ajax_get_filter_options']);
|
|
add_action('wp_ajax_nopriv_hvac_get_filter_options', [$this, 'ajax_get_filter_options']);
|
|
|
|
add_action('wp_ajax_hvac_get_trainer_profile', [$this, 'ajax_get_trainer_profile']);
|
|
add_action('wp_ajax_nopriv_hvac_get_trainer_profile', [$this, 'ajax_get_trainer_profile']);
|
|
|
|
add_action('wp_ajax_hvac_search_trainers', [$this, 'ajax_search_trainers']);
|
|
add_action('wp_ajax_nopriv_hvac_search_trainers', [$this, 'ajax_search_trainers']);
|
|
|
|
// Clear cache on profile updates
|
|
add_action('save_post_trainer_profile', [$this, 'clear_cache']);
|
|
add_action('deleted_post', [$this, 'clear_cache']);
|
|
}
|
|
|
|
/**
|
|
* Get trainers based on filters
|
|
*
|
|
* @param array $args Query arguments
|
|
* @return array
|
|
*/
|
|
public function get_trainers($args = []) {
|
|
$defaults = [
|
|
'per_page' => 12,
|
|
'page' => 1,
|
|
'state' => '',
|
|
'business_type' => '',
|
|
'training_format' => '',
|
|
'training_resources' => '',
|
|
'search' => '',
|
|
'orderby' => 'name',
|
|
'order' => 'ASC'
|
|
];
|
|
|
|
$args = wp_parse_args($args, $defaults);
|
|
|
|
// Generate cache key
|
|
$cache_key = 'trainers_' . md5(serialize($args));
|
|
$cached = wp_cache_get($cache_key, $this->cache_group);
|
|
|
|
if (false !== $cached) {
|
|
return $cached;
|
|
}
|
|
|
|
// Build query
|
|
$query_args = [
|
|
'post_type' => 'trainer_profile',
|
|
'posts_per_page' => $args['per_page'],
|
|
'paged' => $args['page'],
|
|
'post_status' => 'publish',
|
|
'meta_query' => [
|
|
[
|
|
'key' => 'is_public_profile',
|
|
'value' => '1',
|
|
'compare' => '='
|
|
]
|
|
]
|
|
];
|
|
|
|
// Add meta queries
|
|
$meta_query = $this->build_meta_query($args);
|
|
if (!empty($meta_query)) {
|
|
$query_args['meta_query'] = array_merge($query_args['meta_query'], $meta_query);
|
|
}
|
|
|
|
// Add taxonomy queries
|
|
$tax_query = $this->build_tax_query($args);
|
|
if (!empty($tax_query)) {
|
|
$query_args['tax_query'] = $tax_query;
|
|
}
|
|
|
|
// Add search
|
|
if (!empty($args['search'])) {
|
|
$query_args['meta_query'][] = [
|
|
'relation' => 'OR',
|
|
[
|
|
'key' => 'trainer_display_name',
|
|
'value' => $args['search'],
|
|
'compare' => 'LIKE'
|
|
],
|
|
[
|
|
'key' => 'trainer_city',
|
|
'value' => $args['search'],
|
|
'compare' => 'LIKE'
|
|
],
|
|
[
|
|
'key' => 'company_name',
|
|
'value' => $args['search'],
|
|
'compare' => 'LIKE'
|
|
]
|
|
];
|
|
}
|
|
|
|
// Add ordering
|
|
$query_args = $this->add_ordering($query_args, $args['orderby'], $args['order']);
|
|
|
|
// Execute query
|
|
$query = new WP_Query($query_args);
|
|
|
|
$result = [
|
|
'trainers' => [],
|
|
'total' => $query->found_posts,
|
|
'pages' => $query->max_num_pages,
|
|
'current_page' => $args['page']
|
|
];
|
|
|
|
if ($query->have_posts()) {
|
|
while ($query->have_posts()) {
|
|
$query->the_post();
|
|
$result['trainers'][] = $this->format_trainer_data(get_the_ID());
|
|
}
|
|
}
|
|
|
|
wp_reset_postdata();
|
|
|
|
// Cache result
|
|
wp_cache_set($cache_key, $result, $this->cache_group, $this->cache_expiration);
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Build meta query from filters
|
|
*
|
|
* @param array $filters Filter values
|
|
* @return array
|
|
*/
|
|
private function build_meta_query($filters) {
|
|
$meta_query = [];
|
|
|
|
if (!empty($filters['state'])) {
|
|
$meta_query[] = [
|
|
'key' => 'trainer_state',
|
|
'value' => sanitize_text_field($filters['state']),
|
|
'compare' => '='
|
|
];
|
|
}
|
|
|
|
return $meta_query;
|
|
}
|
|
|
|
/**
|
|
* Build taxonomy query from filters
|
|
*
|
|
* @param array $filters Filter values
|
|
* @return array
|
|
*/
|
|
private function build_tax_query($filters) {
|
|
$tax_query = [];
|
|
|
|
if (!empty($filters['business_type'])) {
|
|
$tax_query[] = [
|
|
'taxonomy' => 'business_type',
|
|
'field' => 'slug',
|
|
'terms' => sanitize_text_field($filters['business_type'])
|
|
];
|
|
}
|
|
|
|
if (!empty($filters['training_format'])) {
|
|
$tax_query[] = [
|
|
'taxonomy' => 'training_formats',
|
|
'field' => 'slug',
|
|
'terms' => sanitize_text_field($filters['training_format'])
|
|
];
|
|
}
|
|
|
|
if (!empty($filters['training_resources'])) {
|
|
$tax_query[] = [
|
|
'taxonomy' => 'training_resources',
|
|
'field' => 'slug',
|
|
'terms' => sanitize_text_field($filters['training_resources'])
|
|
];
|
|
}
|
|
|
|
if (!empty($tax_query)) {
|
|
$tax_query['relation'] = 'AND';
|
|
}
|
|
|
|
return $tax_query;
|
|
}
|
|
|
|
/**
|
|
* Add ordering to query
|
|
*
|
|
* @param array $query_args Query arguments
|
|
* @param string $orderby Order by field
|
|
* @param string $order Order direction
|
|
* @return array
|
|
*/
|
|
private function add_ordering($query_args, $orderby, $order) {
|
|
switch ($orderby) {
|
|
case 'name':
|
|
$query_args['meta_key'] = 'trainer_display_name';
|
|
$query_args['orderby'] = 'meta_value';
|
|
break;
|
|
|
|
case 'city':
|
|
$query_args['meta_key'] = 'trainer_city';
|
|
$query_args['orderby'] = 'meta_value';
|
|
break;
|
|
|
|
case 'state':
|
|
$query_args['meta_key'] = 'trainer_state';
|
|
$query_args['orderby'] = 'meta_value';
|
|
break;
|
|
|
|
case 'events':
|
|
$query_args['orderby'] = 'meta_value_num';
|
|
$query_args['meta_key'] = 'total_events_count';
|
|
break;
|
|
|
|
default:
|
|
$query_args['orderby'] = 'date';
|
|
break;
|
|
}
|
|
|
|
$query_args['order'] = in_array($order, ['ASC', 'DESC']) ? $order : 'ASC';
|
|
|
|
return $query_args;
|
|
}
|
|
|
|
/**
|
|
* Format trainer data for response
|
|
*
|
|
* @param int $profile_id Trainer profile post ID
|
|
* @return array
|
|
*/
|
|
private function format_trainer_data($profile_id) {
|
|
$user_id = get_post_meta($profile_id, 'user_id', true);
|
|
|
|
$data = [
|
|
'profile_id' => $profile_id,
|
|
'user_id' => $user_id,
|
|
'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),
|
|
'country' => get_post_meta($profile_id, 'trainer_country', true) ?: 'USA',
|
|
'certification_type' => get_post_meta($profile_id, 'certification_type', true),
|
|
'certification_status' => get_post_meta($profile_id, 'certification_status', true),
|
|
'profile_image' => get_post_meta($profile_id, 'profile_image_url', true),
|
|
'company_name' => get_post_meta($profile_id, 'company_name', true),
|
|
'company_website' => get_post_meta($profile_id, 'company_website', true),
|
|
'phone' => get_post_meta($profile_id, 'trainer_phone', true),
|
|
'email' => get_post_meta($profile_id, 'trainer_email', true),
|
|
'bio' => get_post_meta($profile_id, 'trainer_bio', true),
|
|
'latitude' => get_post_meta($profile_id, 'latitude', true),
|
|
'longitude' => get_post_meta($profile_id, 'longitude', true)
|
|
];
|
|
|
|
// Get taxonomies
|
|
$data['business_type'] = wp_get_post_terms($profile_id, 'business_type', ['fields' => 'names']);
|
|
$data['training_formats'] = wp_get_post_terms($profile_id, 'training_formats', ['fields' => 'names']);
|
|
$data['training_locations'] = wp_get_post_terms($profile_id, 'training_locations', ['fields' => 'names']);
|
|
$data['training_resources'] = wp_get_post_terms($profile_id, 'training_resources', ['fields' => 'names']);
|
|
$data['training_audience'] = wp_get_post_terms($profile_id, 'training_audience', ['fields' => 'names']);
|
|
|
|
// Get upcoming events
|
|
$data['upcoming_events'] = $this->get_trainer_events($user_id);
|
|
$data['total_events'] = get_post_meta($profile_id, 'total_events_count', true) ?: 0;
|
|
|
|
return $data;
|
|
}
|
|
|
|
/**
|
|
* Get trainer's upcoming events
|
|
*
|
|
* @param int $user_id Trainer user ID
|
|
* @return array
|
|
*/
|
|
private function get_trainer_events($user_id, $limit = 5) {
|
|
if (!function_exists('tribe_get_events')) {
|
|
return [];
|
|
}
|
|
|
|
$events = tribe_get_events([
|
|
'author' => $user_id,
|
|
'eventDisplay' => 'upcoming',
|
|
'posts_per_page' => $limit
|
|
]);
|
|
|
|
$formatted_events = [];
|
|
|
|
foreach ($events as $event) {
|
|
$formatted_events[] = [
|
|
'id' => $event->ID,
|
|
'title' => $event->post_title,
|
|
'start_date' => tribe_get_start_date($event->ID, false, 'Y-m-d'),
|
|
'start_time' => tribe_get_start_time($event->ID),
|
|
'end_date' => tribe_get_end_date($event->ID, false, 'Y-m-d'),
|
|
'venue' => tribe_get_venue($event->ID),
|
|
'city' => tribe_get_city($event->ID),
|
|
'state' => tribe_get_state($event->ID),
|
|
'url' => get_permalink($event->ID)
|
|
];
|
|
}
|
|
|
|
return $formatted_events;
|
|
}
|
|
|
|
/**
|
|
* Get filter options for a taxonomy
|
|
*
|
|
* @param string $taxonomy Taxonomy name
|
|
* @return array
|
|
*/
|
|
public function get_filter_options($taxonomy) {
|
|
$valid_taxonomies = [
|
|
'business_type',
|
|
'training_formats',
|
|
'training_locations',
|
|
'training_resources',
|
|
'training_audience'
|
|
];
|
|
|
|
if (!in_array($taxonomy, $valid_taxonomies)) {
|
|
return [];
|
|
}
|
|
|
|
$terms = get_terms([
|
|
'taxonomy' => $taxonomy,
|
|
'hide_empty' => true,
|
|
'orderby' => 'name',
|
|
'order' => 'ASC'
|
|
]);
|
|
|
|
$options = [];
|
|
|
|
if (!is_wp_error($terms)) {
|
|
foreach ($terms as $term) {
|
|
$options[] = [
|
|
'value' => $term->slug,
|
|
'label' => $term->name,
|
|
'count' => $term->count
|
|
];
|
|
}
|
|
}
|
|
|
|
return $options;
|
|
}
|
|
|
|
/**
|
|
* Get state/province options
|
|
*
|
|
* @return array
|
|
*/
|
|
public function get_state_options() {
|
|
global $wpdb;
|
|
|
|
$table = $wpdb->postmeta;
|
|
$states = $wpdb->get_col(
|
|
"SELECT DISTINCT meta_value
|
|
FROM $table
|
|
WHERE meta_key = 'trainer_state'
|
|
AND meta_value != ''
|
|
ORDER BY meta_value ASC"
|
|
);
|
|
|
|
$options = [];
|
|
|
|
foreach ($states as $state) {
|
|
$options[] = [
|
|
'value' => $state,
|
|
'label' => $state
|
|
];
|
|
}
|
|
|
|
return $options;
|
|
}
|
|
|
|
/**
|
|
* AJAX handler for getting filtered trainers
|
|
*/
|
|
public function ajax_get_filtered_trainers() {
|
|
check_ajax_referer('hvac_find_trainer', 'nonce');
|
|
|
|
$filters = $_POST['filters'] ?? [];
|
|
$page = intval($_POST['page'] ?? 1);
|
|
$per_page = intval($_POST['per_page'] ?? 12);
|
|
|
|
$args = [
|
|
'page' => $page,
|
|
'per_page' => $per_page,
|
|
'state' => sanitize_text_field($filters['state'] ?? ''),
|
|
'business_type' => sanitize_text_field($filters['business_type'] ?? ''),
|
|
'training_format' => sanitize_text_field($filters['training_format'] ?? ''),
|
|
'training_resources' => sanitize_text_field($filters['training_resources'] ?? ''),
|
|
'search' => sanitize_text_field($filters['search'] ?? '')
|
|
];
|
|
|
|
$result = $this->get_trainers($args);
|
|
|
|
// Generate HTML for directory
|
|
ob_start();
|
|
if (!empty($result['trainers'])) {
|
|
foreach ($result['trainers'] as $trainer) {
|
|
$this->render_trainer_card($trainer);
|
|
}
|
|
} else {
|
|
echo '<div class="hvac-no-results"><p>No trainers found matching your criteria.</p></div>';
|
|
}
|
|
$html = ob_get_clean();
|
|
|
|
wp_send_json_success([
|
|
'trainers' => $result['trainers'],
|
|
'html' => $html,
|
|
'total' => $result['total'],
|
|
'pages' => $result['pages'],
|
|
'current_page' => $result['current_page']
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* AJAX handler for getting filter options
|
|
*/
|
|
public function ajax_get_filter_options() {
|
|
check_ajax_referer('hvac_find_trainer', 'nonce');
|
|
|
|
$filter_type = sanitize_text_field($_POST['filter_type'] ?? '');
|
|
|
|
if ($filter_type === 'state') {
|
|
$options = $this->get_state_options();
|
|
} else {
|
|
$options = $this->get_filter_options($filter_type);
|
|
}
|
|
|
|
wp_send_json_success(['options' => $options]);
|
|
}
|
|
|
|
/**
|
|
* AJAX handler for getting trainer profile
|
|
*/
|
|
public function ajax_get_trainer_profile() {
|
|
check_ajax_referer('hvac_find_trainer', 'nonce');
|
|
|
|
$profile_id = intval($_POST['profile_id'] ?? 0);
|
|
|
|
if (!$profile_id) {
|
|
wp_send_json_error(['message' => 'Invalid trainer profile']);
|
|
}
|
|
|
|
$trainer_data = $this->format_trainer_data($profile_id);
|
|
|
|
if (empty($trainer_data['name'])) {
|
|
wp_send_json_error(['message' => 'Trainer not found']);
|
|
}
|
|
|
|
// Generate profile HTML
|
|
ob_start();
|
|
$this->render_trainer_profile_modal($trainer_data);
|
|
$html = ob_get_clean();
|
|
|
|
wp_send_json_success([
|
|
'trainer' => $trainer_data,
|
|
'html' => $html
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* AJAX handler for searching trainers
|
|
*/
|
|
public function ajax_search_trainers() {
|
|
check_ajax_referer('hvac_find_trainer', 'nonce');
|
|
|
|
$search = sanitize_text_field($_POST['search'] ?? '');
|
|
|
|
if (strlen($search) < 2) {
|
|
wp_send_json_error(['message' => 'Search term too short']);
|
|
}
|
|
|
|
$result = $this->get_trainers(['search' => $search, 'per_page' => 20]);
|
|
|
|
wp_send_json_success([
|
|
'trainers' => $result['trainers'],
|
|
'total' => $result['total']
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Render trainer card
|
|
*
|
|
* @param array $trainer Trainer data
|
|
*/
|
|
private function render_trainer_card($trainer) {
|
|
?>
|
|
<div class="hvac-trainer-card" data-profile-id="<?php echo esc_attr($trainer['profile_id']); ?>">
|
|
<div class="hvac-trainer-card-inner">
|
|
<div class="hvac-trainer-avatar">
|
|
<?php if ($trainer['profile_image']) : ?>
|
|
<img src="<?php echo esc_url($trainer['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($trainer['profile_id']); ?>">
|
|
<?php echo esc_html($trainer['name']); ?>
|
|
</a>
|
|
</h3>
|
|
<p class="trainer-location">
|
|
<?php echo esc_html($trainer['city']); ?>, <?php echo esc_html($trainer['state']); ?>
|
|
</p>
|
|
<?php if ($trainer['certification_type']) : ?>
|
|
<p class="trainer-certification">
|
|
<?php echo esc_html($trainer['certification_type']); ?>
|
|
</p>
|
|
<?php endif; ?>
|
|
<div class="hvac-trainer-actions">
|
|
<button class="hvac-see-events" data-profile-id="<?php echo esc_attr($trainer['profile_id']); ?>">
|
|
<span class="dashicons dashicons-calendar-alt"></span> See Events
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php
|
|
}
|
|
|
|
/**
|
|
* Render trainer profile modal content
|
|
*
|
|
* @param array $trainer Trainer data
|
|
*/
|
|
private function render_trainer_profile_modal($trainer) {
|
|
?>
|
|
<div class="hvac-trainer-modal-header">
|
|
<h2 id="trainer-modal-title"><?php echo esc_html($trainer['name']); ?></h2>
|
|
<button class="hvac-modal-close" aria-label="Close modal">×</button>
|
|
</div>
|
|
|
|
<div class="hvac-trainer-modal-body">
|
|
<div class="hvac-trainer-profile-section">
|
|
<div class="hvac-trainer-profile-header">
|
|
<?php if ($trainer['profile_image']) : ?>
|
|
<img src="<?php echo esc_url($trainer['profile_image']); ?>" alt="<?php echo esc_attr($trainer['name']); ?>" class="hvac-trainer-profile-image">
|
|
<?php else : ?>
|
|
<div class="hvac-trainer-profile-avatar">
|
|
<span><?php echo esc_html(substr($trainer['name'], 0, 1)); ?></span>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<div class="hvac-trainer-profile-info">
|
|
<p class="hvac-trainer-location">
|
|
<?php echo esc_html($trainer['city']); ?>, <?php echo esc_html($trainer['state']); ?>
|
|
</p>
|
|
|
|
<?php if ($trainer['certification_type']) : ?>
|
|
<p class="hvac-trainer-certification">
|
|
<?php echo esc_html($trainer['certification_type']); ?>
|
|
</p>
|
|
<?php endif; ?>
|
|
|
|
<?php if (!empty($trainer['business_type'])) : ?>
|
|
<p class="hvac-trainer-business-type">
|
|
<?php echo esc_html(implode(', ', $trainer['business_type'])); ?>
|
|
</p>
|
|
<?php endif; ?>
|
|
|
|
<p class="hvac-trainer-events-count">
|
|
Total Training Events: <?php echo esc_html($trainer['total_events']); ?>
|
|
</p>
|
|
</div>
|
|
</div>
|
|
|
|
<?php if (!empty($trainer['training_formats'])) : ?>
|
|
<div class="hvac-trainer-detail">
|
|
<strong>Training Formats:</strong> <?php echo esc_html(implode(', ', $trainer['training_formats'])); ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if (!empty($trainer['training_locations'])) : ?>
|
|
<div class="hvac-trainer-detail">
|
|
<strong>Training Locations:</strong> <?php echo esc_html(implode(', ', $trainer['training_locations'])); ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php if (!empty($trainer['upcoming_events'])) : ?>
|
|
<div class="hvac-trainer-events">
|
|
<h3>Upcoming Events:</h3>
|
|
<ul>
|
|
<?php foreach ($trainer['upcoming_events'] as $event) : ?>
|
|
<li>
|
|
<a href="<?php echo esc_url($event['url']); ?>" target="_blank">
|
|
<?php echo esc_html($event['title']); ?>
|
|
</a>
|
|
- <?php echo esc_html($event['start_date']); ?>
|
|
<?php if ($event['city'] && $event['state']) : ?>
|
|
(<?php echo esc_html($event['city'] . ', ' . $event['state']); ?>)
|
|
<?php endif; ?>
|
|
</li>
|
|
<?php endforeach; ?>
|
|
</ul>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
|
|
<div class="hvac-trainer-contact-section">
|
|
<h3>Contact</h3>
|
|
<form class="hvac-contact-form" data-trainer-id="<?php echo esc_attr($trainer['user_id']); ?>" data-profile-id="<?php echo esc_attr($trainer['profile_id']); ?>">
|
|
<div class="hvac-form-row">
|
|
<div class="hvac-form-field">
|
|
<input type="text" name="first_name" id="contact-first-name" placeholder="First Name" required>
|
|
</div>
|
|
<div class="hvac-form-field">
|
|
<input type="text" name="last_name" id="contact-last-name" placeholder="Last Name" required>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="hvac-form-row">
|
|
<div class="hvac-form-field">
|
|
<input type="email" name="email" id="contact-email" placeholder="Email" required>
|
|
</div>
|
|
<div class="hvac-form-field">
|
|
<input type="tel" name="phone" id="contact-phone" placeholder="Phone Number">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="hvac-form-row">
|
|
<div class="hvac-form-field">
|
|
<input type="text" name="city" id="contact-city" placeholder="City">
|
|
</div>
|
|
<div class="hvac-form-field">
|
|
<input type="text" name="state_province" id="contact-state" placeholder="State/Province">
|
|
</div>
|
|
</div>
|
|
|
|
<div class="hvac-form-field">
|
|
<input type="text" name="company" id="contact-company" placeholder="Company">
|
|
</div>
|
|
|
|
<div class="hvac-form-field">
|
|
<textarea name="message" id="contact-message" placeholder="Message" rows="4"></textarea>
|
|
</div>
|
|
|
|
<div class="hvac-form-submit">
|
|
<button type="submit" class="hvac-contact-submit">Submit</button>
|
|
</div>
|
|
</form>
|
|
|
|
<div class="hvac-contact-success" style="display: none;">
|
|
<p>Your message has been sent! Check your inbox for more details.</p>
|
|
</div>
|
|
|
|
<div class="hvac-contact-error" style="display: none;">
|
|
<p>There was an error sending your message. Please try again.</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<?php
|
|
}
|
|
|
|
/**
|
|
* Clear cache
|
|
*/
|
|
public function clear_cache() {
|
|
// Clear cache using available WordPress functions
|
|
if (function_exists('wp_cache_delete_group')) {
|
|
wp_cache_delete_group($this->cache_group);
|
|
} else {
|
|
// Fallback for older WordPress versions
|
|
wp_cache_flush();
|
|
}
|
|
}
|
|
}
|