check_tables(); if (!$tables_exist) { echo '
Certificate database tables are not properly set up. Please contact the administrator.
'; return; } // Handle certificate generation form submission $generation_results = null; $errors = array(); $success_message = ''; if (isset($_POST['generate_certificates']) && isset($_POST['event_id'])) { // Verify nonce if (!isset($_POST['hvac_certificate_nonce']) || !wp_verify_nonce($_POST['hvac_certificate_nonce'], 'hvac_generate_certificates')) { $errors[] = 'Security verification failed. Please try again.'; } else { $submitted_event_id = absint($_POST['event_id']); $selected_attendees = isset($_POST['attendee_ids']) && is_array($_POST['attendee_ids']) ? array_map('absint', $_POST['attendee_ids']) : array(); $checked_in_only = isset($_POST['checked_in_only']) && $_POST['checked_in_only'] === 'yes'; // Check if any attendees were selected if (empty($selected_attendees)) { $errors[] = 'Please select at least one attendee to generate certificates for.'; } else { // Generate certificates in batch $generation_results = $certificate_generator->generate_certificates_batch( $submitted_event_id, $selected_attendees, array(), // Custom data (none for now) $current_user_id, // Generated by current user $checked_in_only // Only for checked-in attendees if selected ); // Set success message if at least one certificate was generated if ($generation_results['success'] > 0) { $message_parts = array( sprintf('Successfully generated %d certificate(s).', $generation_results['success']) ); if ($generation_results['duplicate'] > 0) { $message_parts[] = sprintf('%d duplicate(s) skipped.', $generation_results['duplicate']); } if ($generation_results['not_checked_in'] > 0) { $message_parts[] = sprintf('%d attendee(s) not checked in.', $generation_results['not_checked_in']); } if ($generation_results['error'] > 0) { $message_parts[] = sprintf('%d error(s).', $generation_results['error']); } $success_message = implode(' ', $message_parts); } elseif ($generation_results['duplicate'] > 0 && $generation_results['error'] === 0 && $generation_results['not_checked_in'] === 0) { $success_message = sprintf( 'No new certificates generated. %d certificate(s) already exist for the selected attendees.', $generation_results['duplicate'] ); } elseif ($generation_results['not_checked_in'] > 0 && $checked_in_only) { $success_message = sprintf( 'No new certificates generated. %d selected attendee(s) have not been checked in.', $generation_results['not_checked_in'] ); } else { $errors[] = 'Failed to generate certificates. Please try again.'; } } } } // Get user's events for the event selection step using direct database query (bypassing TEC interference) global $wpdb; // Build author filter $author_filter = current_user_can('edit_others_posts') ? '' : 'AND post_author = ' . intval($current_user_id); // Get events directly from database $events = $wpdb->get_results( "SELECT ID, post_title, post_date FROM {$wpdb->posts} WHERE post_type = 'tribe_events' AND post_status = 'publish' {$author_filter} ORDER BY post_date DESC" ); // Get attendees for the selected event using direct database query $attendees = array(); if ($event_id > 0) { // Use direct database query to get attendees (both TEC and TPP formats) $tec_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 )); // Convert to format expected by template foreach ($tec_attendees as $attendee) { $attendees[] = array( 'attendee_id' => $attendee->attendee_id, 'event_id' => $attendee->event_id, 'holder_name' => $attendee->holder_name, 'holder_email' => $attendee->holder_email, 'check_in' => intval($attendee->check_in) ); } } // Get header and footer get_header(); // Ensure certificate CSS is loaded wp_enqueue_style( 'hvac-certificates-style', HVAC_CE_PLUGIN_URL . 'assets/css/hvac-certificates.css', ['hvac-common-style'], HVAC_CE_VERSION ); // Ensure dashboard CSS is loaded for proper styling wp_enqueue_style( 'hvac-dashboard-style', HVAC_CE_PLUGIN_URL . 'assets/css/hvac-dashboard.css', ['hvac-common-style'], HVAC_CE_VERSION ); ?>

Create and manage certificates for your event attendees.

Step 1: Select Event

You don't have any events. Create an event first.

0 ? '' : 'style="display: none;"'; ?>>

Step 2: Select Attendees

Check this option to only generate certificates for attendees who have been marked as checked in to the event.

0 && !empty($attendees)) : ?>
certificate_exists($event_id, $attendee['attendee_id']); $certificate_status = $has_certificate ? 'Certificate Issued' : 'No Certificate'; $has_cert_class = $has_certificate ? 'hvac-has-certificate' : ''; ?>
Attendee Email Status Certificate
>
0 && empty($attendees)) : ?>

This event has no attendees.

Certificate Preview

Certificates will be generated based on your template settings.

A professional certificate will be generated based on the default template.

Certificate Management Tools

After generating certificates, you can:

  • View all certificates on the Certificate Reports page
  • Email certificates to attendees directly from the reports page
  • Revoke certificates that were issued incorrectly
  • Download certificates in PDF format for printing or distribution
Error in certificate generation: ' . esc_html($e->getMessage()) . ''; } ?>