upskill-event-manager/templates/certificates/template-generate-certificates.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

534 lines
22 KiB
PHP

<?php
/**
* Simplified Generate Certificates Template
*
* @package HVAC_Community_Events
* @subpackage Templates/Certificates
*/
// Exit if accessed directly
if (!defined('ABSPATH')) {
exit;
}
// Get current user ID
$current_user_id = get_current_user_id();
// Get event ID from URL
$event_id = isset($_GET['event_id']) ? absint($_GET['event_id']) : 0;
// Initialize variables
$events = array();
$attendees = array();
$selected_event_title = '';
try {
// Get user's events directly from database
global $wpdb;
$events = $wpdb->get_results($wpdb->prepare(
"SELECT ID, post_title, post_date
FROM {$wpdb->posts}
WHERE post_type = 'tribe_events'
AND post_author = %d
AND post_status = 'publish'
ORDER BY post_date DESC",
$current_user_id
));
// If event is selected, get attendees
if ($event_id > 0) {
// Verify the event belongs to the current user
$event_found = false;
foreach ($events as $event) {
if ($event->ID == $event_id) {
$event_found = true;
$selected_event_title = $event->post_title;
break;
}
}
if ($event_found) {
// Get attendees using the same query as the AJAX handler
$attendees = $wpdb->get_results($wpdb->prepare(
"SELECT
p.ID as attendee_id,
p.post_parent as event_id,
COALESCE(tec_full_name.meta_value, tpp_full_name.meta_value, tickets_full_name.meta_value, 'Unknown Attendee') as holder_name,
COALESCE(tec_email.meta_value, tpp_email.meta_value, tickets_email.meta_value, tpp_attendee_email.meta_value, 'no-email@example.com') as holder_email,
COALESCE(checked_in.meta_value, '0') as check_in
FROM {$wpdb->posts} p
LEFT JOIN {$wpdb->postmeta} tec_full_name ON p.ID = tec_full_name.post_id AND tec_full_name.meta_key = '_tec_tickets_commerce_full_name'
LEFT JOIN {$wpdb->postmeta} tpp_full_name ON p.ID = tpp_full_name.post_id AND tpp_full_name.meta_key = '_tribe_tpp_full_name'
LEFT JOIN {$wpdb->postmeta} tickets_full_name ON p.ID = tickets_full_name.post_id AND tickets_full_name.meta_key = '_tribe_tickets_full_name'
LEFT JOIN {$wpdb->postmeta} tec_email ON p.ID = tec_email.post_id AND tec_email.meta_key = '_tec_tickets_commerce_email'
LEFT JOIN {$wpdb->postmeta} tpp_email ON p.ID = tpp_email.post_id AND tpp_email.meta_key = '_tribe_tpp_email'
LEFT JOIN {$wpdb->postmeta} tickets_email ON p.ID = tickets_email.post_id AND tickets_email.meta_key = '_tribe_tickets_email'
LEFT JOIN {$wpdb->postmeta} tpp_attendee_email ON p.ID = tpp_attendee_email.post_id AND tpp_attendee_email.meta_key = '_tribe_tpp_attendee_email'
LEFT JOIN {$wpdb->postmeta} checked_in ON p.ID = checked_in.post_id AND checked_in.meta_key = '_tribe_tickets_attendee_checked_in'
WHERE p.post_type IN ('tec_tc_attendee', 'tribe_tpp_attendees')
AND p.post_parent = %d
ORDER BY p.ID ASC",
$event_id
));
// Check certificate status for each attendee
if (!empty($attendees) && class_exists('HVAC_Certificate_Manager')) {
$certificate_manager = HVAC_Certificate_Manager::instance();
foreach ($attendees as $attendee) {
// Get the actual certificate data, not just boolean
$certificate = $certificate_manager->get_certificate_by_attendee($event_id, $attendee->attendee_id);
$attendee->has_certificate = !empty($certificate);
$attendee->certificate_data = $certificate;
}
}
// Log for debugging if needed
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log('Generate Certificates - Event ID: ' . $event_id . ', Attendees: ' . count($attendees));
}
}
}
} catch (Exception $e) {
error_log('Generate Certificates Error: ' . $e->getMessage());
}
?>
<div class="hvac-page-wrapper hvac-generate-certificates-page">
<?php
// Display trainer navigation menu
if (class_exists('HVAC_Menu_System')) {
HVAC_Menu_System::instance()->render_trainer_menu();
}
?>
<?php
// Display breadcrumbs
if (class_exists('HVAC_Breadcrumbs')) {
echo HVAC_Breadcrumbs::instance()->render_breadcrumbs();
}
?>
<div class="hvac-container">
<div class="hvac-content-wrapper">
<!-- Page Header -->
<div class="hvac-dashboard-header">
<h1 class="entry-title">Generate Certificates</h1>
</div>
<div class="hvac-page-header">
<p class="hvac-page-description">Generate certificates for attendees of your events.</p>
</div>
<!-- Step 1: Select Event -->
<div class="hvac-section hvac-step-section">
<h2>Step 1: Select Event</h2>
<?php if (empty($events)) : ?>
<div class="hvac-no-events">
<p>You don't have any events yet. Create your first event to start generating certificates.</p>
<p><a href="<?php echo esc_url(home_url('/manage-event/')); ?>" class="hvac-button hvac-primary">Create Event</a></p>
</div>
<?php else : ?>
<div class="hvac-form-group">
<label for="event_id">Select an event to generate certificates for:</label>
<select name="event_id" id="event_id" class="hvac-select" required>
<option value="">Choose an event...</option>
<?php foreach ($events as $event) : ?>
<option value="<?php echo esc_attr($event->ID); ?>" <?php selected($event_id, $event->ID); ?>>
<?php echo esc_html($event->post_title) . ' (' . date('M j, Y', strtotime($event->post_date)) . ')'; ?>
</option>
<?php endforeach; ?>
</select>
</div>
<?php endif; ?>
</div>
<!-- Step 2: Select Attendees (shown when event is selected) -->
<?php if ($event_id > 0) : ?>
<div class="hvac-section hvac-step-section" id="step-select-attendees">
<h2>Step 2: Select Attendees for "<?php echo esc_html($selected_event_title); ?>"</h2>
<?php if (empty($attendees)) : ?>
<div class="hvac-no-attendees">
<p>This event has no attendees yet.</p>
<p>Attendees are created when people register for your event through the ticket system.</p>
</div>
<?php else : ?>
<form id="generate-certificates-form" method="post" action="">
<?php wp_nonce_field('hvac_generate_certificates', 'hvac_certificate_nonce'); ?>
<input type="hidden" name="event_id" value="<?php echo esc_attr($event_id); ?>">
<input type="hidden" name="generate_certificates" value="1">
<?php
// Count attendees with certificates
$has_certificate_count = 0;
foreach ($attendees as $attendee) {
if (!empty($attendee->has_certificate)) {
$has_certificate_count++;
}
}
if ($has_certificate_count > 0) : ?>
<div class="hvac-notice hvac-notice-info">
<p><strong>Note:</strong> <?php echo $has_certificate_count; ?> attendee(s) already have certificates. These will be skipped to prevent duplicates.</p>
<p>Attendees with existing certificates are marked with ✓ and cannot be selected.</p>
</div>
<?php endif; ?>
<div class="hvac-form-group">
<div class="hvac-table-actions">
<button type="button" class="hvac-button hvac-secondary" id="select-all-attendees">Select All</button>
<button type="button" class="hvac-button hvac-secondary" id="select-checked-in">Select Checked-In Only</button>
<button type="button" class="hvac-button hvac-secondary" id="deselect-all-attendees">Deselect All</button>
</div>
<div class="hvac-attendees-table-wrapper">
<table class="hvac-attendees-table">
<thead>
<tr>
<th class="hvac-checkbox-column">
<input type="checkbox" id="select-all-checkbox">
</th>
<th>Attendee Name</th>
<th>Email</th>
<th>Check-in Status</th>
<th>Certificate Status</th>
</tr>
</thead>
<tbody>
<?php foreach ($attendees as $attendee) :
$checked_in = !empty($attendee->check_in);
$checked_in_class = $checked_in ? 'hvac-checked-in' : '';
$status_class = $checked_in ? 'hvac-status-checked-in' : 'hvac-status-not-checked-in';
$status_text = $checked_in ? 'Checked In' : 'Not Checked In';
$attendee_name = $attendee->holder_name ?: 'Unknown';
$attendee_email = $attendee->holder_email ?: 'No email';
$has_certificate = !empty($attendee->has_certificate);
$cert_status_class = $has_certificate ? 'hvac-has-certificate' : '';
?>
<tr class="<?php echo esc_attr($checked_in_class . ' ' . $cert_status_class); ?>">
<td>
<?php if (!$has_certificate) : ?>
<input type="checkbox"
name="attendee_ids[]"
value="<?php echo esc_attr($attendee->attendee_id); ?>"
class="attendee-checkbox"
<?php echo $checked_in ? 'checked' : ''; ?>>
<?php else : ?>
<span class="hvac-certificate-exists" title="Certificate already generated">✓</span>
<?php endif; ?>
</td>
<td class="hvac-attendee-name-cell">
<?php echo esc_html($attendee_name); ?>
<?php echo hvac_get_attendee_profile_icon($attendee); ?>
</td>
<td><?php echo esc_html($attendee_email); ?></td>
<td>
<span class="<?php echo esc_attr($status_class); ?>">
<?php echo esc_html($status_text); ?>
</span>
</td>
<td>
<?php if ($has_certificate && !empty($attendee->certificate_data)) : ?>
<?php
// Generate secure download URL for the certificate
$certificate_url = '';
if (class_exists('HVAC_Certificate_Security')) {
$security = HVAC_Certificate_Security::instance();
$cert_data = array(
'file_path' => $attendee->certificate_data->file_path,
'event_name' => $selected_event_title,
'attendee_name' => $attendee_name,
'certificate_id' => $attendee->certificate_data->certificate_id
);
$certificate_url = $security->generate_download_token(
$attendee->certificate_data->certificate_id,
$cert_data,
3600 // 1 hour validity
);
}
?>
<?php if ($certificate_url) : ?>
<a href="<?php echo esc_url($certificate_url); ?>"
target="_blank"
class="hvac-certificate-link hvac-status-has-certificate"
title="View certificate">
Certificate Issued
</a>
<?php else : ?>
<span class="hvac-status-has-certificate">Certificate Issued</span>
<?php endif; ?>
<?php else : ?>
<span class="hvac-status-no-certificate">No Certificate</span>
<?php endif; ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
</div>
<div class="hvac-form-group">
<button type="submit" class="hvac-button hvac-primary hvac-large hvac-touch-target" id="generate-certificates-btn">
Generate Certificates for Selected Attendees
</button>
</div>
</form>
<?php endif; ?>
</div>
<?php endif; ?>
<!-- Results Section -->
<div id="generation-results" class="hvac-section" style="display: none;">
<h2>Certificate Generation Results</h2>
<div id="results-content"></div>
</div>
</div>
</div>
<style>
.hvac-container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.hvac-dashboard-header {
margin-bottom: 30px;
}
.hvac-section {
margin-bottom: 30px;
padding: 20px;
background: #f8f9fa;
border-radius: 8px;
border: 1px solid #e9ecef;
}
.hvac-section h2 {
margin: 0 0 20px 0;
color: #007cba;
}
.hvac-form-group {
margin-bottom: 20px;
}
.hvac-form-group label {
display: block;
margin-bottom: 8px;
font-weight: bold;
}
.hvac-select {
width: 100%;
max-width: 500px;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 16px;
}
.hvac-button {
padding: 10px 20px;
background: #007cba;
color: white;
text-decoration: none;
border-radius: 4px;
border: none;
cursor: pointer;
display: inline-block;
font-size: 14px;
}
.hvac-button:hover {
background: #005a87;
color: white;
}
.hvac-button.hvac-secondary {
background: #6c757d;
}
.hvac-button.hvac-secondary:hover {
background: #5a6268;
}
.hvac-button.hvac-large {
padding: 15px 30px;
font-size: 16px;
font-weight: bold;
}
.hvac-touch-target {
min-height: 44px;
min-width: 44px;
}
.hvac-table-actions {
margin-bottom: 15px;
display: flex;
gap: 10px;
flex-wrap: wrap;
}
.hvac-attendees-table {
width: 100%;
border-collapse: collapse;
background: white;
border-radius: 4px;
overflow: hidden;
}
.hvac-attendees-table th,
.hvac-attendees-table td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #ddd;
}
.hvac-attendees-table th {
background: #007cba;
color: white;
font-weight: bold;
}
.hvac-checkbox-column {
width: 50px;
text-align: center;
}
.hvac-checkbox-column input {
margin: 0;
}
.hvac-checked-in {
background-color: #d4edda;
}
.hvac-status-checked-in {
color: #155724;
font-weight: bold;
}
.hvac-status-not-checked-in {
color: #721c24;
}
.hvac-no-events,
.hvac-no-attendees {
text-align: center;
padding: 40px;
background: white;
border-radius: 8px;
border: 2px dashed #ddd;
}
@media (max-width: 768px) {
.hvac-attendees-table {
font-size: 14px;
}
.hvac-attendees-table th,
.hvac-attendees-table td {
padding: 8px;
}
.hvac-table-actions {
flex-direction: column;
}
}
</style>
<script>
jQuery(document).ready(function($) {
// Handle event selection change
$('#event_id').on('change', function() {
var eventId = $(this).val();
if (eventId) {
// Reload page with selected event
window.location.href = window.location.pathname + '?event_id=' + eventId;
}
});
// Select all checkbox functionality
$('#select-all-checkbox').on('change', function() {
$('.attendee-checkbox').prop('checked', this.checked);
});
// Individual checkbox change
$('.attendee-checkbox').on('change', function() {
var totalCheckboxes = $('.attendee-checkbox').length;
var checkedCheckboxes = $('.attendee-checkbox:checked').length;
$('#select-all-checkbox').prop('checked', totalCheckboxes === checkedCheckboxes);
});
// Select all button
$('#select-all-attendees').on('click', function() {
$('.attendee-checkbox').prop('checked', true);
$('#select-all-checkbox').prop('checked', true);
});
// Select checked-in only button
$('#select-checked-in').on('click', function() {
$('.attendee-checkbox').prop('checked', false);
$('.hvac-checked-in .attendee-checkbox').prop('checked', true);
// Update select all checkbox
var totalCheckboxes = $('.attendee-checkbox').length;
var checkedCheckboxes = $('.attendee-checkbox:checked').length;
$('#select-all-checkbox').prop('checked', totalCheckboxes === checkedCheckboxes);
});
// Deselect all button
$('#deselect-all-attendees').on('click', function() {
$('.attendee-checkbox').prop('checked', false);
$('#select-all-checkbox').prop('checked', false);
});
// Form submission
$('#generate-certificates-form').on('submit', function(e) {
e.preventDefault();
var checkedAttendees = $('.attendee-checkbox:checked').length;
if (checkedAttendees === 0) {
alert('Please select at least one attendee to generate certificates for.');
return;
}
if (!confirm('Generate certificates for ' + checkedAttendees + ' selected attendees?')) {
return;
}
var $button = $('#generate-certificates-btn');
var originalText = $button.text();
$button.text('Generating Certificates...').prop('disabled', true);
// Submit form via AJAX (or fall back to regular submission)
var formData = $(this).serialize();
$.ajax({
url: ajaxurl || window.location.href,
type: 'POST',
data: formData,
success: function(response) {
$('#generation-results').show();
$('#results-content').html('<div class="hvac-success">Certificates generated successfully for ' + checkedAttendees + ' attendees!</div>');
$button.text(originalText).prop('disabled', false);
},
error: function() {
// Fall back to regular form submission
document.getElementById('generate-certificates-form').submit();
}
});
});
});
</script>
</div> <!-- .hvac-content-wrapper -->
</div> <!-- .hvac-container -->
</div> <!-- .hvac-page-wrapper -->