', $from_n, $from_e ), sprintf( 'Reply-To: %s', $reply ), ]; $attachments = []; if ( ! empty( $context['booking'] ) && is_array( $context['booking'] ) ) { /** * Filter the attachments for a booking email. Integrations may add * .ics files or other booking-related documents. * * @param string[] $attachments Absolute paths. * @param array $booking */ $attachments = apply_filters( 'bookingistic_email_attachments', $attachments, $context['booking'] ); } $sent = wp_mail( $to, $subject, $body, $headers, $attachments ); // Clean up transient attachment files this plugin wrote (e.g. .ics // temps in the system temp dir). Only files we created are removed. $temp_dir = realpath( get_temp_dir() ); foreach ( $attachments as $file ) { if ( ! is_string( $file ) || ! $temp_dir ) { continue; } $real = realpath( $file ); $name = $real ? basename( $real ) : ''; if ( $real && 0 === strpos( $real, $temp_dir ) && 0 === strpos( $name, 'bookingistic-' ) && substr( $name, -4 ) === '.ics' ) { wp_delete_file( $real ); } } Email_Log_Repository::record( [ 'automation_id' => (int) ( $context['automation_id'] ?? 0 ), 'booking_id' => (int) ( $context['booking_id'] ?? 0 ), 'customer_id' => (int) ( $context['customer_id'] ?? 0 ), 'recipient_email' => $to, 'subject' => $subject, 'status' => $sent ? 'sent' : 'failed', 'error_message' => $sent ? '' : 'wp_mail() returned false', 'sent_at' => current_time( 'mysql', true ), ] ); return (bool) $sent; } }