Files
Digital-Dabei-Hamburg-Job-M…/includes/class-scheduler.php
Viktor Miller 6a2914f5fc feat(06-03): implement async batch email processor callback
Add process_mentor_notification_batch() method to process Action
Scheduler callbacks. Sends German email notifications with job details
(title, location, type, permalink) to batches of opted-in mentors.
Includes rate limit delay (0.1s between emails), error logging for
failures, and unsubscribe hint in email body. Registered callback for
'ddhh_jm_send_mentor_notification_batch' hook.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-01-14 21:09:01 +09:00

191 lines
5.1 KiB
PHP

<?php
/**
* Action Scheduler Helper Class
*
* Manages async background jobs for email batch processing.
*
* @package DDHH_Job_Manager
* @since 1.0.0
*/
// Exit if accessed directly.
defined( 'ABSPATH' ) || exit;
/**
* Class DDHH_JM_Scheduler
*
* Provides API for scheduling async email batch processing via Action Scheduler.
*/
class DDHH_JM_Scheduler {
/**
* Initialize hooks.
*/
public static function setup_hooks() {
// Register async action callback for mentor notification batches
add_action( 'ddhh_jm_send_mentor_notification_batch', array( __CLASS__, 'process_mentor_notification_batch' ), 10, 2 );
}
/**
* Schedule mentor notification batch processing.
*
* Chunks user IDs into batches of 50 and schedules async actions for each batch.
* This prevents email provider limits and timeouts when sending to many mentors.
*
* @param array $user_ids Array of user IDs to notify.
* @param int $job_id Job post ID for the notification.
* @return int Number of batches scheduled.
*/
public static function schedule_mentor_notification_batch( $user_ids, $job_id ) {
if ( empty( $user_ids ) || empty( $job_id ) ) {
error_log( 'DDHH_JM_Scheduler: Cannot schedule batch - missing user IDs or job ID' );
return 0;
}
// Chunk user IDs into batches of 50.
$batches = array_chunk( $user_ids, 50 );
$batch_count = 0;
foreach ( $batches as $batch ) {
// Enqueue async action for this batch.
// Hook: ddhh_jm_send_mentor_notification_batch
// Args: batch of user IDs and job ID
// Group: email-notifications (for organization)
// Unique: true (prevents duplicate scheduling)
// Priority: 10 (standard priority)
as_enqueue_async_action(
'ddhh_jm_send_mentor_notification_batch',
array(
'user_ids' => $batch,
'job_id' => $job_id,
),
'email-notifications',
true,
10
);
$batch_count++;
error_log( sprintf(
'DDHH_JM_Scheduler: Scheduled batch %d with %d users for job ID %d',
$batch_count,
count( $batch ),
$job_id
) );
}
error_log( sprintf(
'DDHH_JM_Scheduler: Scheduled %d total batches for %d users for job ID %d',
$batch_count,
count( $user_ids ),
$job_id
) );
return $batch_count;
}
/**
* Process mentor notification batch (async callback).
*
* Sends emails to batch of users about a newly published job.
* Includes rate limiting delay between sends to avoid provider limits.
*
* @param array $user_ids Array of user IDs in this batch.
* @param int $job_id Job post ID.
*/
public static function process_mentor_notification_batch( $user_ids, $job_id ) {
// Validate inputs
if ( empty( $user_ids ) || empty( $job_id ) ) {
error_log( 'DDHH_JM_Scheduler: Cannot process batch - missing user IDs or job ID' );
return;
}
// Get job post
$post = get_post( $job_id );
if ( ! $post || 'job_offer' !== $post->post_type ) {
error_log( sprintf( 'DDHH_JM_Scheduler: Invalid job_id %d in batch processing', $job_id ) );
return;
}
// Get job details
$job_title = $post->post_title;
$job_location = get_field( 'job_location', $job_id );
$job_type = get_field( 'job_type', $job_id );
$job_link = get_permalink( $job_id );
// Track successful sends
$sent_count = 0;
// Process each user in batch
foreach ( $user_ids as $user_id ) {
// Get user data
$user = get_userdata( $user_id );
if ( ! $user ) {
error_log( sprintf( 'DDHH_JM_Scheduler: User ID %d not found, skipping', $user_id ) );
continue;
}
// Get user email
$user_email = $user->user_email;
if ( empty( $user_email ) ) {
error_log( sprintf( 'DDHH_JM_Scheduler: User ID %d has no email, skipping', $user_id ) );
continue;
}
// Prepare German email subject
$subject = sprintf( 'Neues Stellenangebot: %s', $job_title );
// Prepare German email body
$body = sprintf(
"Hallo,\n\n" .
"ein neues Stellenangebot wurde veröffentlicht:\n\n" .
"Stelle: %s\n" .
"Standort: %s\n" .
"Art: %s\n\n" .
"Sie können das Angebot hier ansehen:\n%s\n\n" .
"Um keine weiteren Benachrichtigungen zu erhalten, können Sie diese in Ihrem Profil deaktivieren.\n\n" .
"---\n" .
"Diese E-Mail wurde automatisch gesendet.",
$job_title,
$job_location ? $job_location : 'Nicht angegeben',
$job_type ? $job_type : 'Nicht angegeben',
$job_link
);
// Set email headers
$headers = array( 'Content-Type: text/html; charset=UTF-8' );
// Convert plain text to HTML with line breaks
$html_body = nl2br( esc_html( $body ) );
// Send email
$sent = wp_mail( $user_email, $subject, $html_body, $headers );
// Log failures
if ( ! $sent ) {
error_log(
sprintf(
'DDHH_JM_Scheduler: Failed to send mentor notification to user %d for job %d',
$user_id,
$job_id
)
);
} else {
$sent_count++;
}
// Rate limit delay: 0.1 seconds between emails
usleep( 100000 );
}
// Log batch completion
error_log(
sprintf(
'DDHH_JM_Scheduler: Processed notification batch: %d emails sent for job %d "%s"',
$sent_count,
$job_id,
$job_title
)
);
}
}