PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.5
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.5
1.6.5 1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 trunk All 48 releases
← All changes | app/Services/Email/EmailNotifications.php +337 -65 1.3.21 → 1.6.5 View file →
@@ -57,10 +57,13 @@
57 57 * Order Renewal -> fluent_cart/subscription_renewed (customer + admin)
58 58 * Order Refunded -> fluent_cart/order_fully_refunded (customer + admin)
59 59 * Order Shipping Status Changed => fluent_cart/shipping_status_changed (customer + admin)
60 60 * Reminder Events:
61 - * - fluent_cart/invoice_reminder_due (@todo uncomment when invoice feature is deployed)
62 - * - fluent_cart/invoice_reminder_overdue (used for payment reminders)
61 + * - fluent_cart/renewal_reminder_due
62 + * - fluent_cart/renewal_reminder_overdue (manual/on-demand payment reminder)
63 + * - fluent_cart/renewal_overdue_first (scheduled, first overdue stage)
64 + * - fluent_cart/renewal_overdue_followup (scheduled, intermediate overdue stages)
65 + * - fluent_cart/renewal_overdue_final (scheduled, last overdue stage)
63 66 * - fluent_cart/subscription_renewal_reminder
64 67 * - fluent_cart/subscription_trial_end_reminder
65 68 */
66 69
@@ -138,8 +141,43 @@
138 141 'email_body' => '',
139 142 'attach_pdf_template' => '',
140 143 ]
141 144 ],
145 + 'subscription_renewal_failed_customer' => [
146 + 'event' => 'subscription_renewal_failed',
147 + 'group' => 'subscription',
148 + 'group_label' => __('Subscription Actions', 'fluent-cart'),
149 + 'title' => __('Notify customer when an automatic renewal charge fails', 'fluent-cart'),
150 + 'description' => __('This email will be sent to the customer when their saved payment method could not be charged for a subscription renewal.', 'fluent-cart'),
151 + 'recipient' => 'customer',
152 + 'smartcode_groups' => [],
153 + 'template_path' => 'subscription.renewal_failed.customer',
154 + 'is_async' => false,
155 + 'settings' => [
156 + 'active' => 'yes',
157 + 'subject' => __('Automatic Payment Failed for Renewal #{{order.invoice_no}}', 'fluent-cart'),
158 + 'is_default_body' => 'yes',
159 + 'email_body' => '',
160 + ]
161 + ],
162 + 'subscription_renewal_failed_admin' => [
163 + 'event' => 'subscription_renewal_failed',
164 + 'group' => 'subscription',
165 + 'group_label' => __('Subscription Actions', 'fluent-cart'),
166 + 'title' => __('Notify admin when an automatic renewal charge fails', 'fluent-cart'),
167 + 'description' => __('This email will be sent to the admin when a saved payment method could not be charged for a subscription renewal.', 'fluent-cart'),
168 + 'recipient' => 'admin',
169 + 'smartcode_groups' => [],
170 + 'template_path' => 'subscription.renewal_failed.admin',
171 + 'pre_header' => __('An automatic subscription renewal charge failed. Review the order in the FluentCart Dashboard.', 'fluent-cart'),
172 + 'is_async' => false,
173 + 'settings' => [
174 + 'active' => 'no',
175 + 'subject' => __('Automatic Charge Failed for Renewal #{{order.invoice_no}}', 'fluent-cart'),
176 + 'is_default_body' => 'yes',
177 + 'email_body' => '',
178 + ]
179 + ],
142 180 'subscription_canceled_customer' => [
143 181 'event' => 'subscription_canceled',
144 182 'group' => 'subscription',
145 183 'group_label' => __('Subscription Actions', 'fluent-cart'),
@@ -173,8 +211,25 @@
173 211 'is_default_body' => 'yes',
174 212 'email_body' => '',
175 213 ]
176 214 ],
215 + 'subscription_period_skipped_customer' => [
216 + 'event' => 'subscription_period_skipped',
217 + 'group' => 'subscription',
218 + 'group_label' => __('Subscription Actions', 'fluent-cart'),
219 + 'title' => __('Notify customer when a billing period is skipped', 'fluent-cart'),
220 + 'description' => __('This email will be sent to the customer when an admin skips their next billing period. The internal reason and actor are never included. Off by default.', 'fluent-cart'),
221 + 'recipient' => 'customer',
222 + 'smartcode_groups' => [],
223 + 'template_path' => 'subscription.period_skipped.customer',
224 + 'is_async' => false,
225 + 'settings' => [
226 + 'active' => 'no',
227 + 'subject' => __('Your next payment has been skipped on {{settings.store_name}}', 'fluent-cart'),
228 + 'is_default_body' => 'yes',
229 + 'email_body' => '',
230 + ]
231 + ],
177 232 'order_refunded_admin' => [
178 233 'event' => 'order_refunded',
179 234 'group' => 'order',
180 235 'group_label' => __('Order Actions', 'fluent-cart'),
@@ -284,42 +339,132 @@
284 339 'email_body' => '',
285 340 'attach_pdf_template' => '',
286 341 ]
287 342 ],
288 - // @todo uncomment when invoice feature is deployed
289 - // 'invoice_reminder_due_customer' => [
290 - // 'event' => 'invoice_reminder_due',
291 - // 'title' => __('Invoice due reminder to customer', 'fluent-cart'),
292 - // 'description' => __('This email will be sent before/at invoice due date when payment is pending.', 'fluent-cart'),
293 - // 'recipient' => 'customer',
294 - // 'smartcode_groups' => [],
295 - // 'template_path' => 'order.reminder.due.customer',
296 - // 'is_async' => false,
297 - // 'settings' => [
298 - // 'active' => 'yes',
299 - // 'subject' => __('Payment Reminder #{{order.invoice_no}}', 'fluent-cart'),
300 - // 'is_default_body' => 'yes',
301 - // 'email_body' => '',
302 - // ]
303 - // ],
304 - // 'invoice_reminder_due_admin' => [
305 - // 'event' => 'invoice_reminder_due',
306 - // 'title' => __('Invoice due reminder copy to admin', 'fluent-cart'),
307 - // 'description' => __('This email will be sent to admin when a due reminder is sent to customer.', 'fluent-cart'),
308 - // 'recipient' => 'admin',
309 - // 'smartcode_groups' => [],
310 - // 'template_path' => 'order.reminder.due.admin',
311 - // 'pre_header' => 'An invoice due reminder was sent to a customer. Review the order details in this email or visit FluentCart Dashboard.',
312 - // 'is_async' => false,
313 - // 'settings' => [
314 - // 'active' => 'no',
315 - // 'subject' => __('Invoice Reminder Sent #{{order.invoice_no}}', 'fluent-cart'),
316 - // 'is_default_body' => 'yes',
317 - // 'email_body' => '',
318 - // ]
319 - // ],
320 - 'invoice_reminder_overdue_customer' => [
321 - 'event' => 'invoice_reminder_overdue',
343 + 'renewal_created_admin' => [
344 + 'event' => 'renewal_created',
345 + 'group' => 'manual_subscription',
346 + 'group_label' => __('Store-Managed Renewals', 'fluent-cart'),
347 + 'title' => __('Notify admin when a renewal order is created', 'fluent-cart'),
348 + 'description' => __('This email will be sent to the admin when a renewal order is generated for a store-managed subscription.', 'fluent-cart'),
349 + 'recipient' => 'admin',
350 + 'smartcode_groups' => [],
351 + 'template_path' => 'renewal.created.admin',
352 + 'pre_header' => 'A new renewal order has been created for a store-managed subscription. Review it in the FluentCart Dashboard.',
353 + 'is_async' => false,
354 + 'settings' => [
355 + 'active' => 'yes',
356 + 'subject' => __('New Renewal Order Created on {{settings.store_name}}', 'fluent-cart'),
357 + 'is_default_body' => 'yes',
358 + 'email_body' => '',
359 + ]
360 + ],
361 + 'renewal_created_customer' => [
362 + 'event' => 'renewal_created',
363 + 'group' => 'manual_subscription',
364 + 'group_label' => __('Store-Managed Renewals', 'fluent-cart'),
365 + 'title' => __('Send the renewal order to the customer when a renewal order is created', 'fluent-cart'),
366 + 'description' => __('This email will be sent to the customer when a renewal order is generated for a store-managed subscription.', 'fluent-cart'),
367 + 'recipient' => 'customer',
368 + 'smartcode_groups' => [],
369 + 'template_path' => 'renewal.created.customer',
370 + 'is_async' => false,
371 + 'settings' => [
372 + 'active' => 'yes',
373 + 'subject' => __('Your Subscription Renewal #{{order.invoice_no}}', 'fluent-cart'),
374 + 'is_default_body' => 'yes',
375 + 'email_body' => '',
376 + ]
377 + ],
378 + 'system_upcoming_charge_customer' => [
379 + 'event' => 'system_upcoming_charge',
380 + 'group' => 'system_subscription',
381 + 'group_label' => __('Store-Managed Renewals · Auto-Charge', 'fluent-cart'),
382 + 'title' => __('Notify customer before an automatic renewal charge', 'fluent-cart'),
383 + 'description' => __('This email tells the customer the amount and date of the upcoming automatic charge to their saved payment method, when the renewal order is created ahead of the due date.', 'fluent-cart'),
384 + 'recipient' => 'customer',
385 + 'smartcode_groups' => [],
386 + 'template_path' => 'subscription.upcoming_charge.customer',
387 + 'is_async' => false,
388 + 'settings' => [
389 + 'active' => 'yes',
390 + 'subject' => __('Upcoming automatic payment for your subscription', 'fluent-cart'),
391 + 'is_default_body' => 'yes',
392 + 'email_body' => '',
393 + ]
394 + ],
395 + 'system_charge_failed_customer' => [
396 + 'event' => 'system_charge_failed',
397 + 'group' => 'system_subscription',
398 + 'group_label' => __('Store-Managed Renewals · Auto-Charge', 'fluent-cart'),
399 + 'title' => __('Notify customer when an automatic renewal charge fails', 'fluent-cart'),
400 + 'description' => __('This email will be sent to the customer when the saved payment method could not be charged for a renewal order. It includes the failure reason and a Pay Now link.', 'fluent-cart'),
401 + 'recipient' => 'customer',
402 + 'smartcode_groups' => [],
403 + 'template_path' => 'subscription.charge_failed.customer',
404 + 'is_async' => false,
405 + 'settings' => [
406 + 'active' => 'yes',
407 + 'subject' => __('Automatic Payment Failed for Renewal #{{order.invoice_no}}', 'fluent-cart'),
408 + 'is_default_body' => 'yes',
409 + 'email_body' => '',
410 + ]
411 + ],
412 + 'system_charge_failed_admin' => [
413 + 'event' => 'system_charge_failed',
414 + 'group' => 'system_subscription',
415 + 'group_label' => __('Store-Managed Renewals · Auto-Charge', 'fluent-cart'),
416 + 'title' => __('Notify admin when an automatic renewal charge fails', 'fluent-cart'),
417 + 'description' => __('This email will be sent to the admin when a saved payment method could not be charged for a renewal order.', 'fluent-cart'),
418 + 'recipient' => 'admin',
419 + 'smartcode_groups' => [],
420 + 'template_path' => 'subscription.charge_failed.admin',
421 + 'pre_header' => 'An automatic subscription renewal charge failed. Review the renewal order in the FluentCart Dashboard.',
422 + 'is_async' => false,
423 + 'settings' => [
424 + 'active' => 'no',
425 + 'subject' => __('Automatic Charge Failed for Renewal #{{order.invoice_no}}', 'fluent-cart'),
426 + 'is_default_body' => 'yes',
427 + 'email_body' => '',
428 + ]
429 + ],
430 + 'renewal_reminder_due_admin' => [
431 + 'event' => 'renewal_reminder_due',
432 + 'group' => 'manual_subscription',
433 + 'group_label' => __('Store-Managed Renewals', 'fluent-cart'),
434 + 'title' => __('Renewal due reminder copy to admin', 'fluent-cart'),
435 + 'description' => __('This email will be sent to admin when a due reminder is sent to customer.', 'fluent-cart'),
436 + 'recipient' => 'admin',
437 + 'smartcode_groups' => [],
438 + 'template_path' => 'order.reminder.due.admin',
439 + 'pre_header' => 'A renewal due reminder was sent to a customer. Review the order details in this email or visit FluentCart Dashboard.',
440 + 'is_async' => false,
441 + 'settings' => [
442 + 'active' => 'no',
443 + 'subject' => __('Renewal Reminder Sent #{{order.invoice_no}}', 'fluent-cart'),
444 + 'is_default_body' => 'yes',
445 + 'email_body' => '',
446 + ]
447 + ],
448 + 'renewal_reminder_due_customer' => [
449 + 'event' => 'renewal_reminder_due',
450 + 'group' => 'manual_subscription',
451 + 'group_label' => __('Store-Managed Renewals', 'fluent-cart'),
452 + 'title' => __('Renewal due reminder to customer', 'fluent-cart'),
453 + 'description' => __('This email will be sent before/at renewal due date when payment is pending.', 'fluent-cart'),
454 + 'recipient' => 'customer',
455 + 'smartcode_groups' => [],
456 + 'template_path' => 'order.reminder.due.customer',
457 + 'is_async' => false,
458 + 'settings' => [
459 + 'active' => 'yes',
460 + 'subject' => __('Payment Reminder #{{order.invoice_no}}', 'fluent-cart'),
461 + 'is_default_body' => 'yes',
462 + 'email_body' => '',
463 + ]
464 + ],
465 + 'renewal_reminder_overdue_customer' => [
466 + 'event' => 'renewal_reminder_overdue',
322 467 'group' => 'scheduler',
323 468 'group_label' => __('Scheduler / Reminder Actions', 'fluent-cart'),
324 469 'title' => __('Payment reminder to customer', 'fluent-cart'),
325 470 'description' => __('This email will be sent to remind customer about pending payment.', 'fluent-cart'),
@@ -334,21 +479,39 @@
334 479 'is_default_body' => 'yes',
335 480 'email_body' => '',
336 481 ]
337 482 ],
338 - 'subscription_renewal_reminder_customer' => [
339 - 'event' => 'subscription_renewal_reminder',
340 - 'group' => 'scheduler',
341 - 'group_label' => __('Scheduler / Reminder Actions', 'fluent-cart'),
342 - 'title' => __('Upcoming renewal reminder to customer', 'fluent-cart'),
343 - 'description' => __('This email will be sent before subscription auto-renewal date.', 'fluent-cart'),
483 + 'subscription_past_due_admin' => [
484 + 'event' => 'subscription_past_due',
485 + 'group' => 'subscription',
486 + 'group_label' => __('Subscription Actions', 'fluent-cart'),
487 + 'title' => __('Notify admin when a subscription is past due', 'fluent-cart'),
488 + 'description' => __('This email will be sent to the admin when a subscription is marked as past due.', 'fluent-cart'),
489 + 'recipient' => 'admin',
490 + 'smartcode_groups' => [],
491 + 'template_path' => 'subscription.past_due.admin',
492 + 'pre_header' => 'A subscription payment is past due. Review the subscription details in this email or visit FluentCart Dashboard.',
493 + 'is_async' => false,
494 + 'settings' => [
495 + 'active' => 'no',
496 + 'subject' => __('Subscription Past Due #{{order.invoice_no}}', 'fluent-cart'),
497 + 'is_default_body' => 'yes',
498 + 'email_body' => '',
499 + ]
500 + ],
501 + 'subscription_past_due_customer' => [
502 + 'event' => 'subscription_past_due',
503 + 'group' => 'subscription',
504 + 'group_label' => __('Subscription Actions', 'fluent-cart'),
505 + 'title' => __('Notify customer when subscription is past due', 'fluent-cart'),
506 + 'description' => __('This email will be sent to the customer when their subscription is marked as past due.', 'fluent-cart'),
344 507 'recipient' => 'customer',
345 508 'smartcode_groups' => [],
346 - 'template_path' => 'subscription.reminder.customer',
509 + 'template_path' => 'subscription.past_due.customer',
347 510 'is_async' => false,
348 511 'settings' => [
349 512 'active' => 'yes',
350 - 'subject' => __('Upcoming Renewal Reminder from {{settings.store_name}}', 'fluent-cart'),
513 + 'subject' => __('Your Subscription is Past Due on {{settings.store_name}}', 'fluent-cart'),
351 514 'is_default_body' => 'yes',
352 515 'email_body' => '',
353 516 ]
354 517 ],
@@ -369,26 +532,77 @@
369 532 'is_default_body' => 'yes',
370 533 'email_body' => '',
371 534 ]
372 535 ],
373 - 'subscription_trial_end_reminder_customer' => [
374 - 'event' => 'subscription_trial_end_reminder',
536 + 'subscription_renewal_reminder_customer' => [
537 + 'event' => 'subscription_renewal_reminder',
375 538 'group' => 'scheduler',
376 539 'group_label' => __('Scheduler / Reminder Actions', 'fluent-cart'),
377 - 'title' => __('Trial ending soon reminder to customer', 'fluent-cart'),
378 - 'description' => __('This email will be sent before a trial period ends and converts to a paid subscription.', 'fluent-cart'),
540 + 'title' => __('Upcoming renewal reminder to customer', 'fluent-cart'),
541 + 'description' => __('This email will be sent before subscription auto-renewal date.', 'fluent-cart'),
379 542 'recipient' => 'customer',
380 543 'smartcode_groups' => [],
381 - 'template_path' => 'subscription.trial_end.customer',
544 + 'template_path' => 'subscription.reminder.customer',
382 545 'is_async' => false,
383 546 'settings' => [
384 547 'active' => 'yes',
385 - 'subject' => __('Your Trial is Ending Soon - {{settings.store_name}}', 'fluent-cart'),
548 + 'subject' => __('Upcoming Renewal Reminder from {{settings.store_name}}', 'fluent-cart'),
386 549 'is_default_body' => 'yes',
387 550 'email_body' => '',
388 551 ]
389 552 ],
390 - 'subscription_trial_end_reminder_admin' => [
553 + 'renewal_overdue_first_customer' => [
554 + 'event' => 'renewal_overdue_first',
555 + 'group' => 'scheduler',
556 + 'group_label' => __('Scheduler / Reminder Actions', 'fluent-cart'),
557 + 'title' => __('First overdue renewal reminder to customer', 'fluent-cart'),
558 + 'description' => __('This email will be sent at the first overdue reminder day after a renewal due date while the payment is still pending.', 'fluent-cart'),
559 + 'recipient' => 'customer',
560 + 'smartcode_groups' => [],
561 + 'template_path' => 'order.reminder.renewal_overdue.first.customer',
562 + 'is_async' => false,
563 + 'settings' => [
564 + 'active' => 'yes',
565 + 'subject' => __('Payment Reminder for Renewal #{{order.order_ref}}', 'fluent-cart'),
566 + 'is_default_body' => 'yes',
567 + 'email_body' => '',
568 + ]
569 + ],
570 + 'renewal_overdue_followup_customer' => [
571 + 'event' => 'renewal_overdue_followup',
572 + 'group' => 'scheduler',
573 + 'group_label' => __('Scheduler / Reminder Actions', 'fluent-cart'),
574 + 'title' => __('Follow-up overdue renewal reminder to customer', 'fluent-cart'),
575 + 'description' => __('This email will be sent at the intermediate overdue reminder days while the renewal payment remains pending.', 'fluent-cart'),
576 + 'recipient' => 'customer',
577 + 'smartcode_groups' => [],
578 + 'template_path' => 'order.reminder.renewal_overdue.followup.customer',
579 + 'is_async' => false,
580 + 'settings' => [
581 + 'active' => 'yes',
582 + 'subject' => __('Payment Overdue for Renewal #{{order.order_ref}}', 'fluent-cart'),
583 + 'is_default_body' => 'yes',
584 + 'email_body' => '',
585 + ]
586 + ],
587 + 'renewal_overdue_final_customer' => [
588 + 'event' => 'renewal_overdue_final',
589 + 'group' => 'scheduler',
590 + 'group_label' => __('Scheduler / Reminder Actions', 'fluent-cart'),
591 + 'title' => __('Final overdue renewal notice to customer', 'fluent-cart'),
592 + 'description' => __('This email will be sent at the last configured overdue reminder day while the renewal payment is still pending.', 'fluent-cart'),
593 + 'recipient' => 'customer',
594 + 'smartcode_groups' => [],
595 + 'template_path' => 'order.reminder.renewal_overdue.final.customer',
596 + 'is_async' => false,
597 + 'settings' => [
598 + 'active' => 'yes',
599 + 'subject' => __('Final Notice: Payment Overdue for Renewal #{{order.order_ref}}', 'fluent-cart'),
600 + 'is_default_body' => 'yes',
601 + 'email_body' => '',
602 + ]
603 + ],
604 + 'subscription_trial_end_reminder_admin' => [
391 605 'event' => 'subscription_trial_end_reminder',
392 606 'group' => 'scheduler',
393 607 'group_label' => __('Scheduler / Reminder Actions', 'fluent-cart'),
394 608 'title' => __('Trial ending soon reminder copy to admin', 'fluent-cart'),
@@ -404,8 +618,25 @@
404 618 'is_default_body' => 'yes',
405 619 'email_body' => '',
406 620 ]
407 621 ],
622 + 'subscription_trial_end_reminder_customer' => [
623 + 'event' => 'subscription_trial_end_reminder',
624 + 'group' => 'scheduler',
625 + 'group_label' => __('Scheduler / Reminder Actions', 'fluent-cart'),
626 + 'title' => __('Trial ending soon reminder to customer', 'fluent-cart'),
627 + 'description' => __('This email will be sent before a trial period ends and converts to a paid subscription.', 'fluent-cart'),
628 + 'recipient' => 'customer',
629 + 'smartcode_groups' => [],
630 + 'template_path' => 'subscription.trial_end.customer',
631 + 'is_async' => false,
632 + 'settings' => [
633 + 'active' => 'yes',
634 + 'subject' => __('Your Trial is Ending Soon - {{settings.store_name}}', 'fluent-cart'),
635 + 'is_default_body' => 'yes',
636 + 'email_body' => '',
637 + ]
638 + ],
408 639 ];
409 640
410 641 }
411 642
@@ -427,9 +658,9 @@
427 658
428 659 $settings = Arr::get($notification, 'settings');
429 660
430 661 // Skip active check for on-demand notifications (offline payments, payment reminders)
431 - if (in_array($notification['event'], ['order_placed_offline', 'invoice_reminder_overdue']) || Arr::get($settings, 'active') === 'yes') {
662 + if (in_array($notification['event'], ['order_placed_offline', 'renewal_reminder_overdue']) || Arr::get($settings, 'active') === 'yes') {
432 663 // Continue with normal flow
433 664 } else {
434 665 continue;
435 666 }
@@ -434,17 +665,16 @@
434 665 continue;
435 666 }
436 667 $recipient = Arr::get($notification, 'recipient');
437 668
438 - if (!in_array($recipient, ['admin', 'customer', 'user', 'subscriber'])) {
669 + // A notification that declares its own `to` carries its recipient
670 + // with it, so the whitelist — which only describes the recipients
671 + // core knows how to resolve — does not apply to it.
672 + if (!Arr::get($notification, 'to') && !in_array($recipient, ['admin', 'customer', 'user', 'subscriber'])) {
439 673 continue;
440 674 }
441 675
442 - if ($recipient === 'admin') {
443 - $toEmail = Arr::get($mailingSettings, 'admin_email', '');
444 - } else {
445 - $toEmail = self::EMAIL_RECIPIENT_MAP[$recipient];
446 - }
676 + $toEmail = static::resolveRecipientTemplate($notification, $mailingSettings);
447 677
448 678 if (empty($toEmail)) {
449 679 continue;
450 680 }
@@ -459,15 +689,10 @@
459 689 {
460 690 $settings = Arr::get($notification, 'settings');
461 691 $mailingSettings = static::getSettings();
462 692
463 -
464 693 $recipient = Arr::get($notification, 'recipient');
465 - if ($recipient === 'admin') {
466 - $toEmail = Arr::get($mailingSettings, 'admin_email', '');
467 - } else {
468 - $toEmail = self::EMAIL_RECIPIENT_MAP[$recipient];
469 - }
694 + $toEmail = static::resolveRecipientTemplate($notification, $mailingSettings);
470 695
471 696
472 697 $isDefaultEmailBody = Arr::get($settings, 'is_default_body', 'yes') === 'yes' || empty(Arr::get($settings, 'email_body'));
473 698
@@ -482,11 +707,58 @@
482 707 'is_async' => $notification['is_async'],
483 708 'subject' => Arr::get($settings, 'subject'),
484 709 'is_custom' => !$isDefaultEmailBody,
485 710 'settings' => $settings,
711 + // Carried through so send-time consumers can tell one notification
712 + // from another, and admin-bound mail from customer-bound — see the
713 + // admin recipient filter in parseEmailContent().
714 + 'name' => Arr::get($notification, 'name', ''),
715 + 'event' => Arr::get($notification, 'event', ''),
716 + 'recipient' => $recipient,
486 717 ];
487 718 }
488 719
720 + /**
721 + * Resolve the recipient template for a notification.
722 + *
723 + * A notification may declare its own `to` — a smartcode template, or a
724 + * literal address — which wins outright. Add-ons need this: they register
725 + * notifications that are not order-bound, and the built-in customer
726 + * recipient resolves to {{order.customer.email}}, which has nothing to read
727 + * from without an order.
728 + *
729 + * Falling back to the recipient map keeps every core notification, and any
730 + * add-on that does not declare `to`, on exactly the path it used before.
731 + *
732 + * The returned value is a template — parseEmailContent() runs it through
733 + * the shortcode parser before use. A declared `to` is returned as given:
734 + * wp_mail() accepts an array of recipients as well as a comma-separated
735 + * string, so an array is passed through rather than flattened.
736 + *
737 + * @param array $notification
738 + * @param array|null $mailingSettings resolved settings, passed in to avoid a repeat lookup in loops
739 + * @return string|array
740 + */
741 + public static function resolveRecipientTemplate($notification, $mailingSettings = null)
742 + {
743 + $declaredTo = Arr::get($notification, 'to', '');
744 + if (!empty($declaredTo)) {
745 + return $declaredTo;
746 + }
747 +
748 + if ($mailingSettings === null) {
749 + $mailingSettings = static::getSettings();
750 + }
751 +
752 + $recipient = Arr::get($notification, 'recipient');
753 +
754 + if ($recipient === 'admin') {
755 + return (string)Arr::get($mailingSettings, 'admin_email', '');
756 + }
757 +
758 + return (string)Arr::get(self::EMAIL_RECIPIENT_MAP, $recipient, '');
759 + }
760 +
489 761 public static function getNotification($name)
490 762 {
491 763 $notifications = static::getNotifications();
492 764 return Arr::get($notifications, $name);
@@ -508,9 +780,9 @@
508 780 'active',
509 781 'subject',
510 782 'email_body',
511 783 'is_default_body',
512 - 'attach_pdf_template'
784 + 'attach_pdf_template',
513 785 ];
514 786 $allConfig = static::getSettings();
515 787 $config = static::getNotificationConfig($name);
516 788