PluginProbe
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution / 2.2.0
Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution v2.2.0
2.4.0 2.3.0 2.2.5 2.2.0 2.1.2 2.1.1 trunk 1.10.0 1.10.01 1.10.02 1.5.0 1.5.01 1.5.02 1.5.1 1.5.10 1.5.20 1.5.21 1.5.22 1.5.23 1.5.24 1.5.25 1.6.0 1.7.0 1.7.1 1.7.2 All 33 releases
fluent-booking / app / Services / EmailNotificationService.php

EmailNotificationService.php in Fluent Booking – The Ultimate Appointments Scheduling, Events Booking, Events Calendar Solution 2.2.0, at app/Services/EmailNotificationService.php

474 lines 18.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentBooking\App\Services;
4
5 use FluentBooking\App\App;
6 use FluentBooking\App\Models\Booking;
7 use FluentBooking\App\Services\Libs\Emogrifier\Emogrifier;
8 use FluentBooking\Framework\Support\Arr;
9
10 class EmailNotificationService
11 {
12 /**
13 * @param \FluentBooking\App\Models\Booking $booking
14 * @param $email
15 * @param $emailTo
16 * @param $actionType
17 * @param bool $resending
18 * @return bool|mixed
19 */
20 public static function emailOnBooked(Booking $booking, $email, $emailTo, $actionType = 'scheduled', $resending = false)
21 {
22 $emailSubject = EditorShortCodeParser::parse($email['subject'], $booking);
23 $emailBody = EditorShortCodeParser::parse($email['body'], $booking);
24
25 $globalSettings = Helper::getGlobalSettings();
26 $useHostName = Arr::get($globalSettings, 'emailing.use_host_name', 'no');
27 $useHostEmailOnReply = Arr::get($globalSettings, 'emailing.use_host_email_on_reply', 'no');
28 $attachIcsFile = Arr::get($globalSettings, 'emailing.attach_ics_on_confirmation', 'no');
29 $settingsFromName = Arr::get($globalSettings, 'emailing.from_name', '');
30 $settingsFromEmail = Arr::get($globalSettings, 'emailing.from_email', '');
31 $settingsReplyToName = Arr::get($globalSettings, 'emailing.reply_to_name', '');
32 $settingsReplyToEmail = Arr::get($globalSettings, 'emailing.reply_to_email', '');
33
34 $attachments = [];
35 if ($attachIcsFile == 'yes' && $actionType == 'scheduled' && !$resending) {
36 $attachments = self::prepareAttachments($booking);
37 }
38
39 $guestAddress = self::getGuestAddress($booking);
40
41 $authors = $booking->getHostsDetails(false);
42
43 if ($emailTo == 'guest') {
44 $authors = [$authors[0]];
45 }
46
47 $to = [];
48 $from = '';
49 $replyTo = '';
50 $result = false;
51
52 foreach ($authors as $author) {
53 $hostName = $author['name'] ?? '';
54 $hostAddress = $author['email'];
55
56 $settingsFromEmail = $settingsFromEmail ?: $author['email'];
57 $settingsReplyToEmail = $settingsReplyToEmail ?: $author['email'];
58
59 if ('guest' == $emailTo) {
60 $to[] = $guestAddress;
61 $replyName = $useHostName == 'yes' ? $hostName : $settingsReplyToName;
62 $fromName = $useHostName == 'yes' ? $hostName : $settingsFromName;
63
64 $replyToEmail = $useHostEmailOnReply == 'yes' ? $author['email'] : $settingsReplyToEmail;
65 $replyFromEmail = $useHostEmailOnReply == 'yes' ? $replyToEmail : $settingsFromEmail;
66
67 $replyTo = sprintf('%1s <%2s>', $replyName, $replyToEmail);
68 $from = sprintf('%1s <%2s>', $fromName, $replyFromEmail);
69 } else {
70 $to[] = $hostName ? sprintf('%1$s <%2$s>', $hostName, $hostAddress) : $hostAddress;
71 }
72 }
73
74 $to = implode(', ', array_unique($to));
75
76 if ('guest' != $emailTo) {
77 $replyTo = sprintf('%1s <%2s>', $settingsReplyToName, $settingsReplyToEmail ?: $settingsFromEmail);
78 $from = sprintf('%1s <%2s>', $settingsFromName, $settingsFromEmail);
79 }
80
81 $headers = self::prepareEmailHeaders($replyTo, $from, $email);
82
83 $body = (string)App::make('view')->make('emails.template', [
84 'email_body' => $emailBody,
85 'email_footer' => self::getGlobalEmailFooter(),
86 ]);
87
88 $emogrifier = new Emogrifier($body);
89 $emogrifier->disableInvisibleNodeRemoval();
90 $body = (string)$emogrifier->emogrify();
91
92 $result = Mailer::send($to, $emailSubject, $body, $headers, $attachments);
93
94 foreach ($attachments as $attachment) {
95 wp_delete_file($attachment);
96 }
97
98 $actionTypeLabel = $actionType == 'request' ? __('request', 'fluent-booking') : __('scheduled', 'fluent-booking');
99 $recipientLabel = $emailTo == 'guest' ? __('guest', 'fluent-booking') : __('host', 'fluent-booking');
100 $statusLabel = $result ? __('sent', 'fluent-booking') : __('sending failed', 'fluent-booking');
101 $logType = $result ? 'activity' : 'error';
102
103 $title = sprintf(
104 /* translators: %1$s: Action type, %2$s: Status, %3$s: Recipient */
105 __('Booking %1$s email %2$s to %3$s', 'fluent-booking'),
106 $actionTypeLabel,
107 $statusLabel,
108 $recipientLabel
109 );
110
111 self::addLog($title, $title, $booking->id, $logType);
112
113 return $result;
114 }
115
116 /**
117 * @param \FluentBooking\App\Models\Booking $booking
118 * @param $email
119 * @param $emailTo
120 * @return bool|mixed
121 */
122 public static function reminderEmail(Booking $booking, $email, $emailTo)
123 {
124 $globalSettings = Helper::getGlobalSettings();
125 $useHostName = Arr::get($globalSettings, 'emailing.use_host_name', 'no');
126 $useHostEmailOnReply = Arr::get($globalSettings, 'emailing.use_host_email_on_reply', 'no');
127 $settingsFromName = Arr::get($globalSettings, 'emailing.from_name', '');
128 $settingsFromEmail = Arr::get($globalSettings, 'emailing.from_email', '');
129 $settingsReplyToName = Arr::get($globalSettings, 'emailing.reply_to_name', '');
130 $settingsReplyToEmail = Arr::get($globalSettings, 'emailing.reply_to_email', '');
131
132 $guestAddress = self::getGuestAddress($booking);
133
134 $authors = $booking->getHostsDetails(false);
135
136 if ($emailTo == 'guest') {
137 $authors = [$authors[0]];
138 }
139
140 $to = [];
141 $from = '';
142 $replyTo = '';
143 $result = false;
144
145 foreach ($authors as $author) {
146 $hostAddress = $author['email'];
147 $hostName = $author['name'] ?? '';
148
149 $settingsFromEmail = $settingsFromEmail ?: $author['email'];
150 $settingsReplyToEmail = $settingsReplyToEmail ?: $author['email'];
151
152 if ('guest' == $emailTo) {
153 $to[] = $guestAddress;
154 $replyName = $useHostName == 'yes' ? $hostName : $settingsReplyToName;
155 $fromName = $useHostName == 'yes' ? $hostName : $settingsFromName;
156
157 $replyToEmail = $useHostEmailOnReply == 'yes' ? $author['email'] : $settingsReplyToEmail;
158 $fromEmail = $useHostEmailOnReply == 'yes' ? $replyToEmail : $settingsFromEmail;
159
160 $replyTo = sprintf('%1$s <%2$s>', $replyName, $replyToEmail);
161 $from = sprintf('%1$s <%2$s>', $fromName, $fromEmail);
162 } else {
163 $to[] = $hostName ? sprintf('%1$s <%2$s>', $hostName, $hostAddress) : $hostAddress;
164 }
165 }
166
167 $to = implode(', ', array_unique($to));
168
169 if ('guest' != $emailTo) {
170 $replyTo = sprintf('%1s <%2s>', $settingsReplyToName, $settingsReplyToEmail ?: $settingsFromEmail);
171 $from = sprintf('%1s <%2s>', $settingsFromName, $settingsFromEmail);
172 }
173
174 $headers = self::prepareEmailHeaders($replyTo, $from, $email);
175
176 $subject = EditorShortCodeParser::parse($email['subject'], $booking);
177 $html = EditorShortCodeParser::parse($email['body'], $booking);
178
179 $body = (string)App::make('view')->make('emails.template', [
180 'email_body' => $html,
181 'email_footer' => self::getGlobalEmailFooter()
182 ]);
183
184 $emogrifier = new Emogrifier($body);
185 $emogrifier->disableInvisibleNodeRemoval();
186 $body = (string)$emogrifier->emogrify();
187
188 $result = Mailer::send($to, $subject, $body, $headers);
189
190 $recipientLabel = $emailTo == 'guest' ? __('guest', 'fluent-booking') : __('host', 'fluent-booking');
191 $statusLabel = $result ? __('sent', 'fluent-booking') : __('sending failed', 'fluent-booking');
192 $logType = $result ? 'activity' : 'error';
193
194 $title = sprintf(
195 /* translators: %1$s: Status, %2$s: Recipient */
196 __('Booking reminder email %1$s to %2$s', 'fluent-booking'),
197 $statusLabel,
198 $recipientLabel
199 );
200
201 /* translators: %1$s: Status, %2$s: Recipient */
202 $description = sprintf(__('Reminder email %1$s to %2$s.', 'fluent-booking'), $statusLabel, $recipientLabel);
203
204 self::addLog($title, $description, $booking->id, $logType);
205
206 return $result;
207 }
208
209 /**
210 * @param \FluentBooking\App\Models\Booking $booking
211 * @param $email
212 * @param $emailTo
213 * @param $actionType
214 * @return bool|mixed
215 */
216 public static function bookingCancelOrRejectEmail(Booking $booking, $email, $emailTo, $actionType = 'cancel')
217 {
218 $globalSettings = Helper::getGlobalSettings();
219 $useHostName = Arr::get($globalSettings, 'emailing.use_host_name', 'no');
220 $useHostEmailOnReply = Arr::get($globalSettings, 'emailing.use_host_email_on_reply', 'no');
221 $settingsFromName = Arr::get($globalSettings, 'emailing.from_name', '');
222 $settingsFromEmail = Arr::get($globalSettings, 'emailing.from_email', '');
223 $settingsReplyToName = Arr::get($globalSettings, 'emailing.reply_to_name', '');
224 $settingsReplyToEmail = Arr::get($globalSettings, 'emailing.reply_to_email', '');
225
226 $guestAddress = self::getGuestAddress($booking);
227
228 $authors = $booking->getHostsDetails(false);
229
230 if ($emailTo == 'guest') {
231 $authors = [$authors[0]];
232 }
233
234 $to = [];
235 $from = '';
236 $replyTo = '';
237 $result = false;
238
239 foreach ($authors as $author) {
240 $hostAddress = $author['email'];
241 $hostName = $author['name'] ?? '';
242
243 $settingsFromEmail = $settingsFromEmail ?: $author['email'];
244 $settingsReplyToEmail = $settingsReplyToEmail ?: $author['email'];
245
246 if ('guest' == $emailTo) {
247 $to[] = $guestAddress;
248 $replyName = $useHostName == 'yes' ? $hostName : $settingsReplyToName;
249 $fromName = $useHostName == 'yes' ? $hostName : $settingsFromName;
250
251 $replyToEmail = $useHostEmailOnReply == 'yes' ? $author['email'] : $settingsReplyToEmail;
252 $replyFromEmail = $useHostEmailOnReply == 'yes' ? $replyToEmail : $settingsFromEmail;
253
254 $replyTo = sprintf('%1s <%2s>', $replyName, $replyToEmail);
255 $from = sprintf('%1s <%2s>', $fromName, $replyFromEmail);
256 } else {
257 $to[] = $hostName ? sprintf('%1s <%2s>', $hostName, $hostAddress) : $hostAddress;
258 }
259 }
260
261 $to = implode(', ', array_unique($to));
262
263 if ('guest' != $emailTo) {
264 $replyTo = sprintf('%1s <%2s>', $settingsReplyToName, $settingsReplyToEmail ?: $settingsFromEmail);
265 $from = sprintf('%1s <%2s>', $settingsFromName, $settingsFromEmail);
266 }
267
268 $headers = self::prepareEmailHeaders($replyTo, $from, $email);
269
270 $subject = EditorShortCodeParser::parse($email['subject'], $booking);
271 $html = EditorShortCodeParser::parse($email['body'], $booking);
272
273 $body = (string)App::make('view')->make('emails.template', [
274 'email_body' => $html,
275 'email_footer' => self::getGlobalEmailFooter()
276 ]);
277
278 $emogrifier = new Emogrifier($body);
279 $emogrifier->disableInvisibleNodeRemoval();
280 $body = (string)$emogrifier->emogrify();
281
282 $result = Mailer::send($to, $subject, $body, $headers);
283
284 $actionTypeLabel = $actionType == 'reject' ? __('Rejection', 'fluent-booking') : __('Cancellation', 'fluent-booking');
285 $recipientLabel = $emailTo == 'guest' ? __('guest', 'fluent-booking') : __('host', 'fluent-booking');
286 $statusLabel = $result ? __('sent', 'fluent-booking') : __('sending failed', 'fluent-booking');
287 $logType = $result ? 'activity' : 'error';
288
289 $title = sprintf(
290 /* translators: %1$s: Action type, %2$s: Status, %3$s: Recipient */
291 __('Booking %1$s email %2$s to %3$s', 'fluent-booking'),
292 $actionTypeLabel,
293 $statusLabel,
294 $recipientLabel
295 );
296
297 self::addLog($title, $title, $booking->id, $logType);
298
299 return $result;
300 }
301
302 /**
303 * @param \FluentBooking\App\Models\Booking $booking
304 * @param $email
305 * @param $emailTo
306 * @return bool|mixed
307 */
308 public static function bookingRescheduledEmail(Booking $booking, $email, $emailTo)
309 {
310 $globalSettings = Helper::getGlobalSettings();
311 $useHostName = Arr::get($globalSettings, 'emailing.use_host_name', 'no');
312 $useHostEmailOnReply = Arr::get($globalSettings, 'emailing.use_host_email_on_reply', 'no');
313 $attachIcsFile = Arr::get($globalSettings, 'emailing.attach_ics_on_confirmation', 'no');
314 $settingsFromName = Arr::get($globalSettings, 'emailing.from_name', '');
315 $settingsFromEmail = Arr::get($globalSettings, 'emailing.from_email', '');
316 $settingsReplyToName = Arr::get($globalSettings, 'emailing.reply_to_name', '');
317 $settingsReplyToEmail = Arr::get($globalSettings, 'emailing.reply_to_email', '');
318
319 $attachments = [];
320 if ($attachIcsFile == 'yes') {
321 $attachments = self::prepareAttachments($booking);
322 }
323
324 $guestAddress = self::getGuestAddress($booking);
325
326 $authors = $booking->getHostsDetails(false);
327
328 if ($emailTo == 'guest') {
329 $authors = [$authors[0]];
330 }
331
332 $to = [];
333 $from = '';
334 $replyTo = '';
335 $result = false;
336
337 foreach ($authors as $author) {
338 $hostAddress = $author['email'];
339 $hostName = $author['name'] ?? '';
340
341 $settingsFromEmail = $settingsFromEmail ?: $author['email'];
342 $settingsReplyToEmail = $settingsReplyToEmail ?: $author['email'];
343
344 if ('guest' == $emailTo) {
345 $to[] = $guestAddress;
346 $replyName = $useHostName == 'yes' ? $hostName : $settingsReplyToName;
347 $fromName = $useHostName == 'yes' ? $hostName : $settingsFromName;
348
349 $replyToEmail = $useHostEmailOnReply == 'yes' ? $author['email'] : $settingsReplyToEmail;
350 $replyFromEmail = $useHostEmailOnReply == 'yes' ? $replyToEmail : $settingsFromEmail;
351
352 $replyTo = sprintf('%1s <%2s>', $replyName, $replyToEmail);
353 $from = sprintf('%1s <%2s>', $fromName, $replyFromEmail);
354 } else {
355 $to[] = $hostName ? sprintf('%1$s <%2$s>', $hostName, $hostAddress) : $hostAddress;
356 }
357 }
358
359 $to = implode(', ', array_unique($to));
360
361 if ('guest' != $emailTo) {
362 $replyTo = sprintf('%1s <%2s>', $settingsReplyToName, $settingsReplyToEmail ?: $settingsFromEmail);
363 $from = sprintf('%1s <%2s>', $settingsFromName, $settingsFromEmail);
364 }
365
366 $headers = self::prepareEmailHeaders($replyTo, $from, $email);
367
368 $subject = EditorShortCodeParser::parse($email['subject'], $booking);
369 $html = EditorShortCodeParser::parse($email['body'], $booking);
370
371 $body = (string)App::make('view')->make('emails.template', [
372 'email_body' => $html,
373 'email_footer' => self::getGlobalEmailFooter()
374 ]);
375
376 $emogrifier = new Emogrifier($body);
377 $emogrifier->disableInvisibleNodeRemoval();
378 $body = (string)$emogrifier->emogrify();
379
380 $result = Mailer::send($to, $subject, $body, $headers, $attachments);
381
382 if ($attachments) {
383 wp_delete_file($attachments[0]);
384 }
385
386 $statusLabel = $result ? __('sent', 'fluent-booking') : __('sending failed', 'fluent-booking');
387 $recipientLabel = $emailTo == 'guest' ? __('guest', 'fluent-booking') : __('host', 'fluent-booking');
388 $logType = $result ? 'activity' : 'error';
389
390 $title = sprintf(
391 /* translators: %1$s: Status, %2$s: Recipient */
392 __('Rescheduled booking email %1$s to %2$s', 'fluent-booking'),
393 $statusLabel,
394 $recipientLabel
395 );
396
397 /* translators: %1$s: Status, %2$s: Recipient */
398 $description = sprintf(__('Rescheduling email %1$s to %2$s', 'fluent-booking'), $statusLabel, $recipientLabel);
399
400 self::addLog($title, $description, $booking->id, $logType);
401
402 return $result;
403 }
404
405 private static function getGuestAddress($booking)
406 {
407 $guestAddress = $booking->email;
408 if ($booking->first_name && $booking->last_name) {
409 $guestAddress = sprintf('%1s %2s <%3s>', $booking->first_name, $booking->last_name, $booking->email);
410 } else if ($booking->first_name) {
411 $guestAddress = sprintf('%1s <%2s>', $booking->first_name, $booking->email);
412 }
413
414 if ($additionalGuests = $booking->getAdditionalGuests()) {
415 $guestAddress .= ', ' . implode(', ', $additionalGuests);
416 }
417 return $guestAddress;
418 }
419
420 private static function prepareEmailHeaders($replyTo, $from, $email)
421 {
422 $headers = [
423 'Reply-To: ' . $replyTo
424 ];
425
426 if ($from) {
427 $headers[] = 'From: ' . $from;
428 }
429
430 if (isset($email['recipients'])) {
431 $headers[] = 'bcc: ' . implode(', ', $email['recipients']);
432 }
433
434 return $headers;
435 }
436
437 private static function prepareAttachments($booking)
438 {
439 require_once ABSPATH . 'wp-admin/includes/file.php';
440
441 if (!WP_Filesystem()) {
442 return [];
443 }
444
445 $icsContent = BookingService::generateBookingICS($booking);
446
447 $icsFileName = 'fcal-' . md5(wp_generate_uuid4()) . '.ics';
448 $filePath = trailingslashit(wp_upload_dir()['path']) . $icsFileName;
449
450 global $wp_filesystem;
451 $wp_filesystem->put_contents($filePath, $icsContent);
452
453 return [$filePath];
454 }
455
456 protected static function addLog($title, $description, $bookingId, $type = 'activity')
457 {
458 do_action('fluent_booking/log_booking_note', [
459 'title' => $title,
460 'description' => $description,
461 'booking_id' => $bookingId,
462 'type' => $type,
463 ]);
464 }
465
466 public static function getGlobalEmailFooter()
467 {
468 $globalSettings = Helper::getGlobalSettings();
469
470 return Arr::get($globalSettings, 'emailing.email_footer', '');
471 }
472
473 }
474