feat: Enhance certificate design with logo, trainer name, and improved attendee name retrieval
- Add Upskill HVAC logo support with multiple fallback paths - Display instructor/trainer name prominently on certificates - Fix attendee name retrieval by checking all possible meta keys used by TEC plugins - Improve certificate layout with decorative elements - Increase attendee name font size for better visibility - Add comprehensive fallbacks for missing attendee data Co-Authored-By: Ben Reed <ben@tealmaker.com>
This commit is contained in:
		
							parent
							
								
									3ea3135468
								
							
						
					
					
						commit
						9e44217c5e
					
				
					 1 changed files with 225 additions and 40 deletions
				
			
		|  | @ -337,23 +337,26 @@ class HVAC_Certificate_Generator { | |||
|         // Set background image if available
 | ||||
|         $this->add_certificate_background($pdf); | ||||
|          | ||||
|         // Add Upskill HVAC logo at the top
 | ||||
|         $this->add_upskill_logo($pdf); | ||||
|          | ||||
|         // Certificate title
 | ||||
|         $pdf->SetFont('helvetica', 'B', 30); | ||||
|         $pdf->SetTextColor(0, 77, 155); // Blue
 | ||||
|         $pdf->SetY(30); | ||||
|         $pdf->SetY(45); // Moved down to accommodate logo
 | ||||
|         $pdf->Cell(0, 20, 'CERTIFICATE OF COMPLETION', 0, 1, 'C'); | ||||
|          | ||||
|         // Description text
 | ||||
|         $pdf->SetFont('helvetica', '', 12); | ||||
|         $pdf->SetTextColor(77, 77, 77); // Dark gray
 | ||||
|         $pdf->SetY(55); | ||||
|         $pdf->SetY(70); | ||||
|         $pdf->Cell(0, 10, 'This certificate is awarded to', 0, 1, 'C'); | ||||
|          | ||||
|         // Attendee name
 | ||||
|         // Attendee name - prominently displayed
 | ||||
|         $attendee_name = $certificate_data['attendee_name'] ?? 'Attendee Name'; | ||||
|         $pdf->SetFont('helvetica', 'B', 24); | ||||
|         $pdf->SetFont('helvetica', 'B', 26); | ||||
|         $pdf->SetTextColor(0, 0, 0); // Black
 | ||||
|         $pdf->Cell(0, 15, $attendee_name, 0, 1, 'C'); | ||||
|         $pdf->Cell(0, 20, $attendee_name, 0, 1, 'C'); | ||||
|          | ||||
|         // Course completion text
 | ||||
|         $pdf->SetFont('helvetica', '', 12); | ||||
|  | @ -372,44 +375,52 @@ class HVAC_Certificate_Generator { | |||
|         $pdf->SetTextColor(77, 77, 77); // Dark gray
 | ||||
|         $pdf->Cell(0, 10, 'on ' . $event_date, 0, 1, 'C'); | ||||
|          | ||||
|         // Draw a line
 | ||||
|         // Get instructor/trainer name properly
 | ||||
|         $instructor_name = $certificate_data['instructor_name'] ?? ''; | ||||
|         if (empty($instructor_name) && !empty($certificate_data['trainer_name'])) { | ||||
|             $instructor_name = $certificate_data['trainer_name']; | ||||
|         } | ||||
|         if (empty($instructor_name)) { | ||||
|             // Try to get from event organizer
 | ||||
|             $instructor_name = $certificate_data['organization_name'] ?? 'Instructor'; | ||||
|         } | ||||
|          | ||||
|         // Draw a line for signature
 | ||||
|         $pdf->SetDrawColor(0, 77, 155); // Blue
 | ||||
|         $pdf->SetLineWidth(0.5); | ||||
|         $pdf->Line(70, 150, 190, 150); | ||||
|          | ||||
|         // Instructor name and signature
 | ||||
|         $instructor_name = $certificate_data['instructor_name'] ?? 'Instructor Name'; | ||||
|         $pdf->Line(70, 155, 190, 155); | ||||
|          | ||||
|         // Add instructor signature if available
 | ||||
|         if (!empty($certificate_data['instructor_signature'])) { | ||||
|             $signature_path = $certificate_data['instructor_signature']; | ||||
|             if (file_exists($signature_path)) { | ||||
|                 $pdf->Image($signature_path, 110, 130, 40, 0, '', '', '', false, 300); | ||||
|                 $pdf->Image($signature_path, 110, 135, 40, 0, '', '', '', false, 300); | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         $pdf->SetY(155); | ||||
|         $pdf->SetFont('helvetica', 'B', 12); | ||||
|         // Instructor name and title
 | ||||
|         $pdf->SetY(160); | ||||
|         $pdf->SetFont('helvetica', 'B', 14); | ||||
|         $pdf->SetTextColor(0, 0, 0); // Black
 | ||||
|         $pdf->Cell(0, 10, $instructor_name, 0, 1, 'C'); | ||||
|          | ||||
|         $pdf->SetFont('helvetica', '', 10); | ||||
|         $pdf->SetFont('helvetica', '', 11); | ||||
|         $pdf->SetTextColor(77, 77, 77); // Dark gray
 | ||||
|         $pdf->Cell(0, 10, 'Instructor', 0, 1, 'C'); | ||||
|         $pdf->Cell(0, 8, 'Instructor / Trainer', 0, 1, 'C'); | ||||
|          | ||||
|         // Add organization name
 | ||||
|         $organization_name = $certificate_data['organization_name'] ?? 'Upskill HVAC'; | ||||
|         $pdf->SetY(175); | ||||
|         $pdf->SetFont('helvetica', 'B', 10); | ||||
|         $organization_name = 'Upskill HVAC'; | ||||
|         $pdf->SetY(180); | ||||
|         $pdf->SetFont('helvetica', 'B', 11); | ||||
|         $pdf->SetTextColor(0, 0, 0); // Black
 | ||||
|         $pdf->Cell(0, 10, $organization_name, 0, 1, 'C'); | ||||
|         $pdf->Cell(0, 8, $organization_name, 0, 1, 'C'); | ||||
|          | ||||
|         // Add venue info
 | ||||
|         // Add venue info if available
 | ||||
|         $venue_name = $certificate_data['venue_name'] ?? ''; | ||||
|         if (!empty($venue_name)) { | ||||
|             $pdf->SetFont('helvetica', '', 10); | ||||
|             $pdf->SetTextColor(77, 77, 77); // Dark gray
 | ||||
|             $pdf->Cell(0, 10, $venue_name, 0, 1, 'C'); | ||||
|             $pdf->Cell(0, 8, $venue_name, 0, 1, 'C'); | ||||
|         } | ||||
|          | ||||
|         // Add certificate details at the bottom
 | ||||
|  | @ -418,8 +429,8 @@ class HVAC_Certificate_Generator { | |||
|         $pdf->SetY(195); | ||||
|         $pdf->Cell(0, 10, 'Certificate #: ' . $certificate->certificate_number . ' | Issue Date: ' . date('F j, Y', strtotime($certificate->date_generated)), 0, 1, 'C'); | ||||
|          | ||||
|         // Add logo
 | ||||
|         $this->add_logo($pdf); | ||||
|         // Add decorative elements (optional)
 | ||||
|         $this->add_decorative_elements($pdf); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|  | @ -465,6 +476,72 @@ class HVAC_Certificate_Generator { | |||
|             $pdf->Image($logo_path, 15, 15, 40, 0, '', '', '', false, 300); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * Add Upskill HVAC logo to certificate. | ||||
|      * | ||||
|      * @param TCPDF $pdf The TCPDF instance. | ||||
|      */ | ||||
|     protected function add_upskill_logo($pdf) { | ||||
|         // Check for uploaded logo in WordPress uploads directory
 | ||||
|         $upload_dir = wp_upload_dir(); | ||||
|         $logo_path = $upload_dir['basedir'] . '/2025/05/UpskillHVAC-Logo_Black_NoOutline.png'; | ||||
|          | ||||
|         // Fallback to 2024 directory if 2025 doesn't exist
 | ||||
|         if (!file_exists($logo_path)) { | ||||
|             $logo_path = $upload_dir['basedir'] . '/2024/05/UpskillHVAC-Logo_Black_NoOutline.png'; | ||||
|         } | ||||
|          | ||||
|         // Check plugin assets directory as another fallback
 | ||||
|         if (!file_exists($logo_path)) { | ||||
|             $logo_path = HVAC_CE_PLUGIN_DIR . 'assets/images/upskill-hvac-logo.png'; | ||||
|         } | ||||
|          | ||||
|         if (file_exists($logo_path)) { | ||||
|             // Add logo at top center
 | ||||
|             // Calculate center position - assuming letter size landscape (279.4mm wide)
 | ||||
|             $page_width = $pdf->getPageWidth(); | ||||
|             $logo_width = 50; // 50mm wide logo
 | ||||
|             $x_position = ($page_width - $logo_width) / 2; | ||||
|              | ||||
|             $pdf->Image($logo_path, $x_position, 10, $logo_width, 0, '', '', '', false, 300); | ||||
|         } else { | ||||
|             // If no logo found, add text branding
 | ||||
|             $pdf->SetFont('helvetica', 'B', 16); | ||||
|             $pdf->SetTextColor(0, 77, 155); // Blue
 | ||||
|             $pdf->SetY(15); | ||||
|             $pdf->Cell(0, 10, 'UPSKILL HVAC', 0, 1, 'C'); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     /** | ||||
|      * Add decorative elements to certificate. | ||||
|      * | ||||
|      * @param TCPDF $pdf The TCPDF instance. | ||||
|      */ | ||||
|     protected function add_decorative_elements($pdf) { | ||||
|         // Add decorative corner elements
 | ||||
|         $pdf->SetDrawColor(0, 77, 155); // Blue
 | ||||
|         $pdf->SetLineWidth(0.5); | ||||
|          | ||||
|         // Top left corner
 | ||||
|         $pdf->Line(10, 10, 30, 10); | ||||
|         $pdf->Line(10, 10, 10, 30); | ||||
|          | ||||
|         // Top right corner
 | ||||
|         $page_width = $pdf->getPageWidth(); | ||||
|         $pdf->Line($page_width - 30, 10, $page_width - 10, 10); | ||||
|         $pdf->Line($page_width - 10, 10, $page_width - 10, 30); | ||||
|          | ||||
|         // Bottom left corner
 | ||||
|         $page_height = $pdf->getPageHeight(); | ||||
|         $pdf->Line(10, $page_height - 30, 10, $page_height - 10); | ||||
|         $pdf->Line(10, $page_height - 10, 30, $page_height - 10); | ||||
|          | ||||
|         // Bottom right corner
 | ||||
|         $pdf->Line($page_width - 30, $page_height - 10, $page_width - 10, $page_height - 10); | ||||
|         $pdf->Line($page_width - 10, $page_height - 30, $page_width - 10, $page_height - 10); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get attendee data from Event Tickets. | ||||
|  | @ -483,12 +560,91 @@ class HVAC_Certificate_Generator { | |||
|             return $attendee_data; | ||||
|         } | ||||
|          | ||||
|         // Get attendee meta for Event Tickets
 | ||||
|         $attendee_name = get_post_meta($attendee_id, '_tribe_tickets_full_name', true); | ||||
|         $attendee_email = get_post_meta($attendee_id, '_tribe_tickets_email', true); | ||||
|         $user_id = 0; | ||||
|         // Try multiple meta keys for attendee name (matching the template query)
 | ||||
|         $meta_keys_for_name = array( | ||||
|             '_tec_tickets_commerce_full_name',  // TEC Commerce
 | ||||
|             '_tribe_tpp_full_name',              // Tribe PayPal Tickets
 | ||||
|             '_tribe_tickets_full_name',          // Event Tickets
 | ||||
|             '_tribe_rsvp_full_name',             // RSVP
 | ||||
|             'attendee_full_name',                // Legacy
 | ||||
|             '_name',                             // Generic
 | ||||
|             'name'                               // Generic
 | ||||
|         ); | ||||
|          | ||||
|         $attendee_name = ''; | ||||
|         foreach ($meta_keys_for_name as $meta_key) { | ||||
|             $name = get_post_meta($attendee_id, $meta_key, true); | ||||
|             if (!empty($name)) { | ||||
|                 $attendee_name = $name; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         // If still no name, try first and last name separately
 | ||||
|         if (empty($attendee_name)) { | ||||
|             $first_name_keys = array( | ||||
|                 '_tribe_tickets_first_name', | ||||
|                 '_tribe_tpp_first_name', | ||||
|                 '_tec_tickets_commerce_first_name', | ||||
|                 'attendee_first_name', | ||||
|                 'first_name' | ||||
|             ); | ||||
|              | ||||
|             $last_name_keys = array( | ||||
|                 '_tribe_tickets_last_name', | ||||
|                 '_tribe_tpp_last_name', | ||||
|                 '_tec_tickets_commerce_last_name', | ||||
|                 'attendee_last_name', | ||||
|                 'last_name' | ||||
|             ); | ||||
|              | ||||
|             $first_name = ''; | ||||
|             $last_name = ''; | ||||
|              | ||||
|             foreach ($first_name_keys as $key) { | ||||
|                 $fname = get_post_meta($attendee_id, $key, true); | ||||
|                 if (!empty($fname)) { | ||||
|                     $first_name = $fname; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|             foreach ($last_name_keys as $key) { | ||||
|                 $lname = get_post_meta($attendee_id, $key, true); | ||||
|                 if (!empty($lname)) { | ||||
|                     $last_name = $lname; | ||||
|                     break; | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|             if (!empty($first_name) || !empty($last_name)) { | ||||
|                 $attendee_name = trim($first_name . ' ' . $last_name); | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         // Try multiple meta keys for email (matching the template query)
 | ||||
|         $meta_keys_for_email = array( | ||||
|             '_tec_tickets_commerce_email', | ||||
|             '_tribe_tpp_email', | ||||
|             '_tribe_tickets_email', | ||||
|             '_tribe_tpp_attendee_email', | ||||
|             '_tribe_rsvp_email', | ||||
|             'attendee_email', | ||||
|             '_email', | ||||
|             'email' | ||||
|         ); | ||||
|          | ||||
|         $attendee_email = ''; | ||||
|         foreach ($meta_keys_for_email as $meta_key) { | ||||
|             $email = get_post_meta($attendee_id, $meta_key, true); | ||||
|             if (!empty($email) && is_email($email)) { | ||||
|                 $attendee_email = $email; | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         // Try to find user by email
 | ||||
|         $user_id = 0; | ||||
|         if (!empty($attendee_email)) { | ||||
|             $user = get_user_by('email', $attendee_email); | ||||
|             if ($user) { | ||||
|  | @ -496,18 +652,13 @@ class HVAC_Certificate_Generator { | |||
|             } | ||||
|         } | ||||
|          | ||||
|         // If name is empty, try alternative meta keys
 | ||||
|         // If still no name, use email prefix or "Attendee"
 | ||||
|         if (empty($attendee_name)) { | ||||
|             $attendee_name = get_post_meta($attendee_id, '_tribe_rsvp_full_name', true); | ||||
|              | ||||
|             // If still empty, check for first and last name separately
 | ||||
|             if (empty($attendee_name)) { | ||||
|                 $first_name = get_post_meta($attendee_id, '_tribe_tickets_first_name', true); | ||||
|                 $last_name = get_post_meta($attendee_id, '_tribe_tickets_last_name', true); | ||||
|                  | ||||
|                 if (!empty($first_name) || !empty($last_name)) { | ||||
|                     $attendee_name = trim($first_name . ' ' . $last_name); | ||||
|                 } | ||||
|             if (!empty($attendee_email)) { | ||||
|                 $email_parts = explode('@', $attendee_email); | ||||
|                 $attendee_name = ucwords(str_replace(array('.', '_', '-'), ' ', $email_parts[0])); | ||||
|             } else { | ||||
|                 $attendee_name = 'Attendee #' . $attendee_id; | ||||
|             } | ||||
|         } | ||||
|          | ||||
|  | @ -519,6 +670,11 @@ class HVAC_Certificate_Generator { | |||
|             'user_id' => $user_id | ||||
|         ); | ||||
|          | ||||
|         // Log for debugging
 | ||||
|         if (defined('WP_DEBUG') && WP_DEBUG && empty($attendee_name)) { | ||||
|             error_log("Certificate Generator: No name found for attendee ID $attendee_id"); | ||||
|         } | ||||
|          | ||||
|         return $attendee_data; | ||||
|     } | ||||
| 
 | ||||
|  | @ -550,7 +706,34 @@ class HVAC_Certificate_Generator { | |||
|         // Get organizer details
 | ||||
|         $organizer_id = tribe_get_organizer_id($event_id); | ||||
|         $organizer_name = tribe_get_organizer($event_id); | ||||
|         $instructor_name = $organizer_name; // Default instructor is the organizer
 | ||||
|          | ||||
|         // Get trainer/instructor name
 | ||||
|         // First check if this event has a trainer/author
 | ||||
|         $trainer_id = $event->post_author; | ||||
|         $trainer = get_userdata($trainer_id); | ||||
|         $instructor_name = ''; | ||||
|          | ||||
|         if ($trainer) { | ||||
|             // Try to get display name first
 | ||||
|             $instructor_name = $trainer->display_name; | ||||
|              | ||||
|             // If no display name, try full name
 | ||||
|             if (empty($instructor_name) || $instructor_name == $trainer->user_login) { | ||||
|                 $first_name = get_user_meta($trainer_id, 'first_name', true); | ||||
|                 $last_name = get_user_meta($trainer_id, 'last_name', true); | ||||
|                 if ($first_name || $last_name) { | ||||
|                     $instructor_name = trim($first_name . ' ' . $last_name); | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|             // Fallback to organizer name if still empty
 | ||||
|             if (empty($instructor_name)) { | ||||
|                 $instructor_name = $organizer_name; | ||||
|             } | ||||
|         } else { | ||||
|             // Use organizer name as fallback
 | ||||
|             $instructor_name = $organizer_name; | ||||
|         } | ||||
|          | ||||
|         // Build event data
 | ||||
|         $event_data = array( | ||||
|  | @ -562,7 +745,9 @@ class HVAC_Certificate_Generator { | |||
|             'venue_name' => $venue_name, | ||||
|             'organizer_id' => $organizer_id, | ||||
|             'organization_name' => $organizer_name, | ||||
|             'instructor_name' => $instructor_name | ||||
|             'instructor_name' => $instructor_name, | ||||
|             'trainer_name' => $instructor_name, // Also include as trainer_name for compatibility
 | ||||
|             'trainer_id' => $trainer_id | ||||
|         ); | ||||
|          | ||||
|         return $event_data; | ||||
|  |  | |||
		Loading…
	
		Reference in a new issue