batch_size = apply_filters('hvac_announcement_email_batch_size', 50); $this->init_hooks(); } /** * Initialize hooks */ private function init_hooks() { // Watch for status changes add_action('transition_post_status', array($this, 'handle_status_transition'), 10, 3); // Cron action for batch sending add_action('hvac_send_announcement_email_batch', array($this, 'send_email_batch'), 10, 2); } /** * Handle post status transitions * * @param string $new_status New post status * @param string $old_status Old post status * @param WP_Post $post Post object */ public function handle_status_transition($new_status, $old_status, $post) { // Only handle our post type if ($post->post_type !== HVAC_Announcements_CPT::get_post_type()) { return; } // Only send email when publishing for the first time if ($new_status === 'publish' && $old_status !== 'publish') { // Check if email was already sent for this announcement $email_sent = get_post_meta($post->ID, '_hvac_announcement_email_sent', true); if (!$email_sent) { $this->queue_announcement_emails($post->ID); } } } /** * Queue announcement emails for batch processing * * @param int $post_id Announcement post ID */ private function queue_announcement_emails($post_id) { // Get active trainers $trainers = HVAC_Announcements_Permissions::get_active_trainers(); if (empty($trainers)) { return; } // Store recipient IDs $recipient_ids = array(); foreach ($trainers as $trainer) { if (HVAC_Announcements_Permissions::user_should_receive_emails($trainer->ID)) { $recipient_ids[] = $trainer->ID; } } // Save recipient list update_post_meta($post_id, '_hvac_announcement_email_recipients', $recipient_ids); update_post_meta($post_id, '_hvac_announcement_email_send_date', current_time('mysql')); // Process in batches $batches = array_chunk($recipient_ids, $this->batch_size); foreach ($batches as $index => $batch) { // Schedule immediate sending (can be delayed using wp_schedule_single_event) wp_schedule_single_event( time() + ($index * 10), // Stagger by 10 seconds per batch 'hvac_send_announcement_email_batch', array($post_id, $batch) ); } } /** * Send email batch * * @param int $post_id Announcement post ID * @param array $recipient_ids Array of user IDs */ public function send_email_batch($post_id, $recipient_ids) { $post = get_post($post_id); if (!$post || $post->post_type !== HVAC_Announcements_CPT::get_post_type()) { return; } // Get email content $subject = $this->get_email_subject($post); $body = $this->get_email_body($post); $headers = $this->get_email_headers(); $successful_sends = array(); $failed_sends = array(); foreach ($recipient_ids as $user_id) { $user = get_user_by('id', $user_id); if (!$user || !$user->user_email) { $failed_sends[] = $user_id; continue; } // Validate email address if (!is_email($user->user_email)) { $failed_sends[] = $user_id; // Log invalid email $this->log_email_send($post_id, $user_id, 'invalid_email'); continue; } // Send email $sent = wp_mail($user->user_email, $subject, $body, $headers); if ($sent) { $successful_sends[] = $user_id; // Log successful send $this->log_email_send($post_id, $user_id, 'success'); } else { $failed_sends[] = $user_id; // Log failed send $this->log_email_send($post_id, $user_id, 'failed'); // Schedule retry (max 3 attempts) $this->maybe_schedule_retry($post_id, $user_id); } } // Mark as sent if all batches are complete $all_sent = get_post_meta($post_id, '_hvac_announcement_email_sent', true); if (!$all_sent && empty($failed_sends)) { update_post_meta($post_id, '_hvac_announcement_email_sent', true); } } /** * Get email subject * * @param WP_Post $post Announcement post * @return string */ private function get_email_subject($post) { $subject = sprintf( 'Upskill HVAC Trainer Announcement: %s', $post->post_title ); return apply_filters('hvac_announcement_email_subject', $subject, $post); } /** * Get email body * * @param WP_Post $post Announcement post * @return string */ private function get_email_body($post) { // Get template $template_path = plugin_dir_path(dirname(__FILE__)) . 'templates/email/announcement-notification.php'; if (!file_exists($template_path)) { // Fallback to simple HTML return $this->get_fallback_email_body($post); } // Start output buffering ob_start(); // Set up template variables $announcement_title = $post->post_title; $announcement_content = apply_filters('the_content', $post->post_content); $publish_date = get_the_date('F j, Y', $post); $site_url = home_url(); $resources_url = home_url('/trainer/resources/'); // Get featured image $featured_image = ''; if (has_post_thumbnail($post->ID)) { $featured_image = get_the_post_thumbnail($post->ID, 'large', array( 'style' => 'max-width: 100%; height: auto; display: block; margin: 20px 0;' )); } // Get categories and tags $categories = wp_get_post_terms($post->ID, HVAC_Announcements_CPT::get_category_taxonomy(), array('fields' => 'names')); $tags = wp_get_post_terms($post->ID, HVAC_Announcements_CPT::get_tag_taxonomy(), array('fields' => 'names')); $categories_tags = ''; if (!empty($categories) || !empty($tags)) { $categories_tags = '
'; if (!empty($categories)) { $categories_tags .= '

Categories: ' . implode(', ', $categories) . '

'; } if (!empty($tags)) { $categories_tags .= '

Tags: ' . implode(', ', $tags) . '

'; } $categories_tags .= '
'; } // Include template include $template_path; // Get output $body = ob_get_clean(); return apply_filters('hvac_announcement_email_body', $body, $post); } /** * Get fallback email body if template doesn't exist * * @param WP_Post $post Announcement post * @return string */ private function get_fallback_email_body($post) { $html = ''; $html .= ''; $html .= '
'; // Header $html .= '
'; $html .= '

Upskill HVAC Trainer Announcement

'; $html .= '
'; // Content $html .= '
'; $html .= '

' . esc_html($post->post_title) . '

'; $html .= '

Posted on ' . get_the_date('F j, Y', $post) . '

'; // Featured image if (has_post_thumbnail($post->ID)) { $html .= get_the_post_thumbnail($post->ID, 'large', array( 'style' => 'max-width: 100%; height: auto; display: block; margin: 20px 0;' )); } // Content $html .= '
'; $html .= apply_filters('the_content', $post->post_content); $html .= '
'; $html .= '
'; // Footer $html .= '
'; $html .= '

You received this email because you are registered as an HVAC Trainer.

'; $html .= '

View all announcements

'; $html .= '
'; $html .= '
'; return $html; } /** * Get email headers * * @return array */ private function get_email_headers() { $admin_email = get_option('admin_email'); // Validate admin email, use fallback if invalid if (!is_email($admin_email)) { // Try to get first administrator's email as fallback $admins = get_users(array('role' => 'administrator', 'number' => 1)); if (!empty($admins) && is_email($admins[0]->user_email)) { $admin_email = $admins[0]->user_email; } else { // Use a generic noreply address as last resort $domain = parse_url(home_url(), PHP_URL_HOST); $admin_email = 'noreply@' . $domain; } } $headers = array( 'Content-Type: text/html; charset=UTF-8', 'From: ' . get_bloginfo('name') . ' <' . $admin_email . '>', ); return apply_filters('hvac_announcement_email_headers', $headers); } /** * Log email send attempt * * @param int $post_id Announcement post ID * @param int $user_id User ID * @param string $status Status (success/failed) */ private function log_email_send($post_id, $user_id, $status) { $log = get_post_meta($post_id, '_hvac_announcement_email_log', true); if (!is_array($log)) { $log = array(); } $log[] = array( 'user_id' => $user_id, 'status' => $status, 'timestamp' => current_time('mysql'), ); update_post_meta($post_id, '_hvac_announcement_email_log', $log); } /** * Maybe schedule retry for failed email * * @param int $post_id Announcement post ID * @param int $user_id User ID */ private function maybe_schedule_retry($post_id, $user_id) { $retry_count = get_user_meta($user_id, '_hvac_announcement_email_retry_' . $post_id, true); if (!$retry_count) { $retry_count = 0; } // Max 3 retries if ($retry_count < 3) { $retry_count++; update_user_meta($user_id, '_hvac_announcement_email_retry_' . $post_id, $retry_count); // Schedule retry in 5 minutes wp_schedule_single_event( time() + (5 * 60), 'hvac_send_announcement_email_batch', array($post_id, array($user_id)) ); } } /** * Get email send status for an announcement * * @param int $post_id Announcement post ID * @return array */ public static function get_email_status($post_id) { $email_sent = get_post_meta($post_id, '_hvac_announcement_email_sent', true); $recipients = get_post_meta($post_id, '_hvac_announcement_email_recipients', true); $send_date = get_post_meta($post_id, '_hvac_announcement_email_send_date', true); $log = get_post_meta($post_id, '_hvac_announcement_email_log', true); $successful = 0; $failed = 0; if (is_array($log)) { foreach ($log as $entry) { if ($entry['status'] === 'success') { $successful++; } else { $failed++; } } } return array( 'sent' => $email_sent, 'total_recipients' => is_array($recipients) ? count($recipients) : 0, 'successful' => $successful, 'failed' => $failed, 'send_date' => $send_date, ); } }