$donation_data Donation data array. * @return bool True if email was sent successfully. * @since 0.0.1 */ public static function send_donation_confirmation( $donation_id, $campaign_id, $donation_data ) { $notification = self::get_notification( 'donation_receipt' ); if ( ! $notification ) { return false; } // Check if donor email is available. $donor_email = isset( $donation_data['donor_email'] ) && is_string( $donation_data['donor_email'] ) ? $donation_data['donor_email'] : ''; if ( empty( $donor_email ) || ! is_email( $donor_email ) ) { return false; } // Get campaign data. $campaign = get_post( $campaign_id ); if ( ! $campaign ) { return false; } // Send donor receipt email. $sent = self::send_email( $donor_email, $notification, $donation_data, $campaign, $donation_id ); // Also send admin notification if enabled. self::send_admin_new_donation( $donation_id, $campaign_id, $donation_data ); return $sent; } /** * Send new donation notification to admin. * * @param int $donation_id Donation ID. * @param int $campaign_id Campaign ID. * @param array $donation_data Donation data array. * @return bool True if email was sent successfully. * @since 0.0.1 */ public static function send_admin_new_donation( $donation_id, $campaign_id, $donation_data ) { $notification = self::get_notification( 'admin_new_donation' ); if ( ! $notification ) { return false; } // Get campaign data. $campaign = get_post( $campaign_id ); if ( ! $campaign ) { return false; } // Send to admin email. $admin_email = get_option( 'admin_email' ); $admin_email = is_string( $admin_email ) ? $admin_email : ''; return self::send_email( $admin_email, $notification, $donation_data, $campaign, $donation_id ); } /** * Get notification settings by type. * * @param string $notification_type Notification type key. * @return array|false Notification settings or false if not found/disabled. * @since 0.0.1 */ private static function get_notification( $notification_type ) { $notifications = Helper::get_suredonation_option( self::OPTION_KEY, [] ); // Ensure notifications is an array before accessing offsets. if ( ! is_array( $notifications ) || empty( $notifications[ $notification_type ] ) ) { return false; } $notification = $notifications[ $notification_type ]; // Ensure notification is an array before accessing offsets. if ( ! is_array( $notification ) ) { return false; } // Check if enabled. if ( empty( $notification['enabled'] ) ) { return false; } return $notification; } /** * Send email using notification settings. * * @param string $to_email Recipient email address. * @param array $notification Notification settings. * @param array $donation_data Donation data for smart tags. * @param \WP_Post $campaign Campaign post object. * @param int $donation_id Optional donation ID. * @return bool True if email was sent successfully. * @since 0.0.1 */ private static function send_email( $to_email, $notification, $donation_data, $campaign, $donation_id = 0 ) { if ( empty( $to_email ) || ! is_email( $to_email ) ) { return false; } // Prepare email data - ensure string types for process_smart_tags. $subject_raw = isset( $notification['subject'] ) && is_string( $notification['subject'] ) ? $notification['subject'] : ''; $email_body_raw = isset( $notification['email_body'] ) && is_string( $notification['email_body'] ) ? $notification['email_body'] : ''; $subject = self::process_smart_tags( $subject_raw, $donation_data, $campaign ); $email_body = self::process_smart_tags( $email_body_raw, $donation_data, $campaign ); // Get from name and email - ensure string types. $from_name_raw = isset( $notification['from_name'] ) && is_string( $notification['from_name'] ) ? $notification['from_name'] : ''; $from_name = ! empty( $from_name_raw ) ? $from_name_raw : get_bloginfo( 'name' ); $from_email = isset( $notification['from_email'] ) && is_string( $notification['from_email'] ) && ! empty( $notification['from_email'] ) ? $notification['from_email'] : get_option( 'admin_email' ); $reply_to = isset( $notification['reply_to'] ) && is_string( $notification['reply_to'] ) && ! empty( $notification['reply_to'] ) ? $notification['reply_to'] : ( is_string( $from_email ) ? $from_email : '' ); // Process smart tags in from fields. $from_name = self::process_smart_tags( is_string( $from_name ) ? $from_name : '', $donation_data, $campaign ); // Ensure from_email and reply_to are strings. $from_email = is_string( $from_email ) ? $from_email : ''; $reply_to = is_string( $reply_to ) ? $reply_to : ''; // Set email headers. $headers = [ 'Content-Type: text/html; charset=UTF-8', sprintf( 'From: %s <%s>', $from_name, $from_email ), sprintf( 'Reply-To: %s', $reply_to ), ]; // Convert plain text to HTML if needed. $email_body = self::format_email_body( $email_body ); // Send email. $sent = wp_mail( $to_email, $subject, $email_body, $headers ); // Log email send attempt. $notification_id = isset( $notification['id'] ) && is_string( $notification['id'] ) ? $notification['id'] : ''; do_action( 'suredonation_email_sent', $donation_id, $to_email, $sent, $notification_id ); return $sent; } /** * Process smart tags in email content. * * @param string $content Content with smart tags. * @param array $donation_data Donation data. * @param \WP_Post $campaign Campaign post object. * @return string Processed content. * @since 0.0.1 */ private static function process_smart_tags( $content, $donation_data, $campaign ) { // Get currency symbol - ensure string type. $currency = isset( $donation_data['currency'] ) && is_string( $donation_data['currency'] ) ? $donation_data['currency'] : 'USD'; // Calculate total amount (base + fees) - ensure numeric types. $amount_value = $donation_data['amount'] ?? 0; $fees_covered_value = $donation_data['fees_covered'] ?? 0; $base_amount = is_numeric( $amount_value ) ? (float) $amount_value : 0.0; $fees_covered = is_numeric( $fees_covered_value ) ? (float) $fees_covered_value : 0.0; $total_amount = $base_amount + $fees_covered; // Format amounts with currency symbol. $formatted_amount = Payment_Helper::format_amount( $total_amount, $currency ); // Get date format - ensure string type. $date_format = get_option( 'date_format' ); $date_format = is_string( $date_format ) ? $date_format : 'Y-m-d'; // Smart tags mapping. $donor_name = isset( $donation_data['donor_name'] ) && is_string( $donation_data['donor_name'] ) ? $donation_data['donor_name'] : __( 'Donor', 'suredonation' ); $donor_email = isset( $donation_data['donor_email'] ) && is_string( $donation_data['donor_email'] ) ? $donation_data['donor_email'] : ''; $transaction_id = isset( $donation_data['transaction_id'] ) && is_string( $donation_data['transaction_id'] ) ? $donation_data['transaction_id'] : ''; if ( empty( $transaction_id ) && isset( $donation_data['id'] ) ) { $transaction_id = is_scalar( $donation_data['id'] ) ? (string) $donation_data['id'] : ''; } $tags = [ '{donor_name}' => $donor_name, '{donor_email}' => $donor_email, '{amount}' => $formatted_amount, '{campaign_name}' => $campaign->post_title, '{donation_date}' => current_time( $date_format ), '{transaction_id}' => $transaction_id, '{site_title}' => get_bloginfo( 'name' ), '{admin_email}' => get_option( 'admin_email' ), '{site_url}' => home_url(), '{admin_url}' => admin_url( 'admin.php?page=suredonation' ), ]; // Apply filters to allow adding custom smart tags. $tags = apply_filters( 'suredonation_email_smart_tags', $tags, $donation_data, $campaign ); // Replace smart tags. return str_replace( array_keys( $tags ), array_values( $tags ), $content ); } /** * Format email body with HTML wrapper. * * @param string $body Email body content. * @return string Formatted HTML email. * @since 0.0.1 */ private static function format_email_body( $body ) { $email_template = Email_Template::get_instance(); return $email_template->render( $body ); } }