PluginProbe
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management / 0.0.1
SureDonation – Donation Forms, Fundraising Campaigns & Donor Management v0.0.1
1.6.1 1.6.0 1.5.1 1.5.0 1.4.0 1.3.0 trunk 0.0.1 1.0.0 1.1.0 1.1.1 1.1.2 1.2.0
suredonation / inc / emails / email-handler.php

email-handler.php in SureDonation – Donation Forms, Fundraising Campaigns & Donor Management 0.0.1, at inc/emails/email-handler.php

265 lines 9.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Email Handler - Sends donation-related emails
4 *
5 * @package SureDonation
6 */
7
8 namespace SureDonation\Inc\Emails;
9
10 use SureDonation\Inc\Helper;
11 use SureDonation\Inc\Payments\Payment_Helper;
12
13 // Exit if accessed directly.
14 if ( ! defined( 'ABSPATH' ) ) {
15 exit;
16 }
17
18 /**
19 * Email_Handler class.
20 *
21 * @since 0.0.1
22 */
23 class Email_Handler {
24 /**
25 * Option key for email notifications within consolidated options.
26 *
27 * @since 0.0.1
28 */
29 public const OPTION_KEY = 'email_notifications';
30
31 /**
32 * Send donation confirmation email to donor.
33 *
34 * @param int $donation_id Donation ID.
35 * @param int $campaign_id Campaign ID.
36 * @param array<string, mixed> $donation_data Donation data array.
37 * @return bool True if email was sent successfully.
38 * @since 0.0.1
39 */
40 public static function send_donation_confirmation( $donation_id, $campaign_id, $donation_data ) {
41 $notification = self::get_notification( 'donation_receipt' );
42
43 if ( ! $notification ) {
44 return false;
45 }
46
47 // Check if donor email is available.
48 $donor_email = isset( $donation_data['donor_email'] ) && is_string( $donation_data['donor_email'] ) ? $donation_data['donor_email'] : '';
49 if ( empty( $donor_email ) || ! is_email( $donor_email ) ) {
50 return false;
51 }
52
53 // Get campaign data.
54 $campaign = get_post( $campaign_id );
55 if ( ! $campaign ) {
56 return false;
57 }
58
59 // Send donor receipt email.
60 $sent = self::send_email(
61 $donor_email,
62 $notification,
63 $donation_data,
64 $campaign,
65 $donation_id
66 );
67
68 // Also send admin notification if enabled.
69 self::send_admin_new_donation( $donation_id, $campaign_id, $donation_data );
70
71 return $sent;
72 }
73
74 /**
75 * Send new donation notification to admin.
76 *
77 * @param int $donation_id Donation ID.
78 * @param int $campaign_id Campaign ID.
79 * @param array<string, mixed> $donation_data Donation data array.
80 * @return bool True if email was sent successfully.
81 * @since 0.0.1
82 */
83 public static function send_admin_new_donation( $donation_id, $campaign_id, $donation_data ) {
84 $notification = self::get_notification( 'admin_new_donation' );
85
86 if ( ! $notification ) {
87 return false;
88 }
89
90 // Get campaign data.
91 $campaign = get_post( $campaign_id );
92 if ( ! $campaign ) {
93 return false;
94 }
95
96 // Send to admin email.
97 $admin_email = get_option( 'admin_email' );
98 $admin_email = is_string( $admin_email ) ? $admin_email : '';
99
100 return self::send_email(
101 $admin_email,
102 $notification,
103 $donation_data,
104 $campaign,
105 $donation_id
106 );
107 }
108
109 /**
110 * Get notification settings by type.
111 *
112 * @param string $notification_type Notification type key.
113 * @return array<string, mixed>|false Notification settings or false if not found/disabled.
114 * @since 0.0.1
115 */
116 private static function get_notification( $notification_type ) {
117 $notifications = Helper::get_suredonation_option( self::OPTION_KEY, [] );
118
119 // Ensure notifications is an array before accessing offsets.
120 if ( ! is_array( $notifications ) || empty( $notifications[ $notification_type ] ) ) {
121 return false;
122 }
123
124 $notification = $notifications[ $notification_type ];
125
126 // Ensure notification is an array before accessing offsets.
127 if ( ! is_array( $notification ) ) {
128 return false;
129 }
130
131 // Check if enabled.
132 if ( empty( $notification['enabled'] ) ) {
133 return false;
134 }
135
136 return $notification;
137 }
138
139 /**
140 * Send email using notification settings.
141 *
142 * @param string $to_email Recipient email address.
143 * @param array<string, mixed> $notification Notification settings.
144 * @param array<string, mixed> $donation_data Donation data for smart tags.
145 * @param \WP_Post $campaign Campaign post object.
146 * @param int $donation_id Optional donation ID.
147 * @return bool True if email was sent successfully.
148 * @since 0.0.1
149 */
150 private static function send_email( $to_email, $notification, $donation_data, $campaign, $donation_id = 0 ) {
151 if ( empty( $to_email ) || ! is_email( $to_email ) ) {
152 return false;
153 }
154
155 // Prepare email data - ensure string types for process_smart_tags.
156 $subject_raw = isset( $notification['subject'] ) && is_string( $notification['subject'] ) ? $notification['subject'] : '';
157 $email_body_raw = isset( $notification['email_body'] ) && is_string( $notification['email_body'] ) ? $notification['email_body'] : '';
158 $subject = self::process_smart_tags( $subject_raw, $donation_data, $campaign );
159 $email_body = self::process_smart_tags( $email_body_raw, $donation_data, $campaign );
160
161 // Get from name and email - ensure string types.
162 $from_name_raw = isset( $notification['from_name'] ) && is_string( $notification['from_name'] ) ? $notification['from_name'] : '';
163 $from_name = ! empty( $from_name_raw ) ? $from_name_raw : get_bloginfo( 'name' );
164 $from_email = isset( $notification['from_email'] ) && is_string( $notification['from_email'] ) && ! empty( $notification['from_email'] )
165 ? $notification['from_email']
166 : get_option( 'admin_email' );
167 $reply_to = isset( $notification['reply_to'] ) && is_string( $notification['reply_to'] ) && ! empty( $notification['reply_to'] )
168 ? $notification['reply_to']
169 : ( is_string( $from_email ) ? $from_email : '' );
170
171 // Process smart tags in from fields.
172 $from_name = self::process_smart_tags( is_string( $from_name ) ? $from_name : '', $donation_data, $campaign );
173
174 // Ensure from_email and reply_to are strings.
175 $from_email = is_string( $from_email ) ? $from_email : '';
176 $reply_to = is_string( $reply_to ) ? $reply_to : '';
177
178 // Set email headers.
179 $headers = [
180 'Content-Type: text/html; charset=UTF-8',
181 sprintf( 'From: %s <%s>', $from_name, $from_email ),
182 sprintf( 'Reply-To: %s', $reply_to ),
183 ];
184
185 // Convert plain text to HTML if needed.
186 $email_body = self::format_email_body( $email_body );
187
188 // Send email.
189 $sent = wp_mail( $to_email, $subject, $email_body, $headers );
190
191 // Log email send attempt.
192 $notification_id = isset( $notification['id'] ) && is_string( $notification['id'] ) ? $notification['id'] : '';
193 do_action( 'suredonation_email_sent', $donation_id, $to_email, $sent, $notification_id );
194
195 return $sent;
196 }
197
198 /**
199 * Process smart tags in email content.
200 *
201 * @param string $content Content with smart tags.
202 * @param array<string, mixed> $donation_data Donation data.
203 * @param \WP_Post $campaign Campaign post object.
204 * @return string Processed content.
205 * @since 0.0.1
206 */
207 private static function process_smart_tags( $content, $donation_data, $campaign ) {
208 // Get currency symbol - ensure string type.
209 $currency = isset( $donation_data['currency'] ) && is_string( $donation_data['currency'] ) ? $donation_data['currency'] : 'USD';
210
211 // Calculate total amount (base + fees) - ensure numeric types.
212 $amount_value = $donation_data['amount'] ?? 0;
213 $fees_covered_value = $donation_data['fees_covered'] ?? 0;
214 $base_amount = is_numeric( $amount_value ) ? (float) $amount_value : 0.0;
215 $fees_covered = is_numeric( $fees_covered_value ) ? (float) $fees_covered_value : 0.0;
216 $total_amount = $base_amount + $fees_covered;
217
218 // Format amounts with currency symbol.
219 $formatted_amount = Payment_Helper::format_amount( $total_amount, $currency );
220
221 // Get date format - ensure string type.
222 $date_format = get_option( 'date_format' );
223 $date_format = is_string( $date_format ) ? $date_format : 'Y-m-d';
224
225 // Smart tags mapping.
226 $donor_name = isset( $donation_data['donor_name'] ) && is_string( $donation_data['donor_name'] ) ? $donation_data['donor_name'] : __( 'Donor', 'suredonation' );
227 $donor_email = isset( $donation_data['donor_email'] ) && is_string( $donation_data['donor_email'] ) ? $donation_data['donor_email'] : '';
228 $transaction_id = isset( $donation_data['transaction_id'] ) && is_string( $donation_data['transaction_id'] ) ? $donation_data['transaction_id'] : '';
229 if ( empty( $transaction_id ) && isset( $donation_data['id'] ) ) {
230 $transaction_id = is_scalar( $donation_data['id'] ) ? (string) $donation_data['id'] : '';
231 }
232
233 $tags = [
234 '{donor_name}' => $donor_name,
235 '{donor_email}' => $donor_email,
236 '{amount}' => $formatted_amount,
237 '{campaign_name}' => $campaign->post_title,
238 '{donation_date}' => current_time( $date_format ),
239 '{transaction_id}' => $transaction_id,
240 '{site_title}' => get_bloginfo( 'name' ),
241 '{admin_email}' => get_option( 'admin_email' ),
242 '{site_url}' => home_url(),
243 '{admin_url}' => admin_url( 'admin.php?page=suredonation' ),
244 ];
245
246 // Apply filters to allow adding custom smart tags.
247 $tags = apply_filters( 'suredonation_email_smart_tags', $tags, $donation_data, $campaign );
248
249 // Replace smart tags.
250 return str_replace( array_keys( $tags ), array_values( $tags ), $content );
251 }
252
253 /**
254 * Format email body with HTML wrapper.
255 *
256 * @param string $body Email body content.
257 * @return string Formatted HTML email.
258 * @since 0.0.1
259 */
260 private static function format_email_body( $body ) {
261 $email_template = Email_Template::get_instance();
262 return $email_template->render( $body );
263 }
264 }
265