PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.7.1
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.7.1
1.7.1 1.7.0 1.6.6 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 All 51 releases
← All changes | app/Services/Email/EmailNotifications.php +181 -1 1.6.3 → 1.7.1 View file →
@@ -1,8 +1,9 @@
1 1 <?php
2 2
3 3 namespace FluentCart\App\Services\Email;
4 4
5 +use FluentCart\Api\ModuleSettings;
5 6 use FluentCart\App\Models\Meta;
6 7 use FluentCart\App\Services\Cache;
7 8 use FluentCart\App\Services\TemplateService;
8 9 use FluentCart\Framework\Support\Arr;
@@ -17,12 +18,24 @@
17 18 ];
18 19
19 20 const META_KEY = 'email_notifications_config';
20 21
22 + /** The events the reviews module raises. */
23 + const REVIEW_EVENTS = ['review_created', 'review_approved_done', 'review_replied_done'];
24 +
21 25 public static function getNotifications(): array
22 26 {
23 27 $settings = static::getDefaultNotifications();
24 28 $settings = apply_filters('fluent_cart/email_notifications', $settings);
29 +
30 + // Review notifications are neither offered nor sent while the module
31 + // is off; their stored settings are kept by name.
32 + if (!ModuleSettings::isActive('reviews')) {
33 + $settings = array_filter($settings, function ($setting) {
34 + return !in_array(Arr::get($setting, 'event'), static::REVIEW_EVENTS, true);
35 + });
36 + }
37 +
25 38 $config = Arr::get(static::cachedSettings(), 'notification_config', []);
26 39
27 40 foreach ($settings as $key => &$setting) {
28 41 $setting['name'] = $key;
@@ -58,9 +71,12 @@
58 71 * Order Refunded -> fluent_cart/order_fully_refunded (customer + admin)
59 72 * Order Shipping Status Changed => fluent_cart/shipping_status_changed (customer + admin)
60 73 * Reminder Events:
61 74 * - fluent_cart/renewal_reminder_due
62 - * - fluent_cart/renewal_reminder_overdue
75 + * - fluent_cart/renewal_reminder_overdue (manual/on-demand payment reminder)
76 + * - fluent_cart/renewal_overdue_first (scheduled, first overdue stage)
77 + * - fluent_cart/renewal_overdue_followup (scheduled, intermediate overdue stages)
78 + * - fluent_cart/renewal_overdue_final (scheduled, last overdue stage)
63 79 * - fluent_cart/subscription_renewal_reminder
64 80 * - fluent_cart/subscription_trial_end_reminder
65 81 */
66 82
@@ -546,8 +562,59 @@
546 562 'is_default_body' => 'yes',
547 563 'email_body' => '',
548 564 ]
549 565 ],
566 + 'renewal_overdue_first_customer' => [
567 + 'event' => 'renewal_overdue_first',
568 + 'group' => 'scheduler',
569 + 'group_label' => __('Scheduler / Reminder Actions', 'fluent-cart'),
570 + 'title' => __('First overdue renewal reminder to customer', 'fluent-cart'),
571 + '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'),
572 + 'recipient' => 'customer',
573 + 'smartcode_groups' => [],
574 + 'template_path' => 'order.reminder.renewal_overdue.first.customer',
575 + 'is_async' => false,
576 + 'settings' => [
577 + 'active' => 'yes',
578 + 'subject' => __('Payment Reminder for Renewal #{{order.order_ref}}', 'fluent-cart'),
579 + 'is_default_body' => 'yes',
580 + 'email_body' => '',
581 + ]
582 + ],
583 + 'renewal_overdue_followup_customer' => [
584 + 'event' => 'renewal_overdue_followup',
585 + 'group' => 'scheduler',
586 + 'group_label' => __('Scheduler / Reminder Actions', 'fluent-cart'),
587 + 'title' => __('Follow-up overdue renewal reminder to customer', 'fluent-cart'),
588 + 'description' => __('This email will be sent at the intermediate overdue reminder days while the renewal payment remains pending.', 'fluent-cart'),
589 + 'recipient' => 'customer',
590 + 'smartcode_groups' => [],
591 + 'template_path' => 'order.reminder.renewal_overdue.followup.customer',
592 + 'is_async' => false,
593 + 'settings' => [
594 + 'active' => 'yes',
595 + 'subject' => __('Payment Overdue for Renewal #{{order.order_ref}}', 'fluent-cart'),
596 + 'is_default_body' => 'yes',
597 + 'email_body' => '',
598 + ]
599 + ],
600 + 'renewal_overdue_final_customer' => [
601 + 'event' => 'renewal_overdue_final',
602 + 'group' => 'scheduler',
603 + 'group_label' => __('Scheduler / Reminder Actions', 'fluent-cart'),
604 + 'title' => __('Final overdue renewal notice to customer', 'fluent-cart'),
605 + 'description' => __('This email will be sent at the last configured overdue reminder day while the renewal payment is still pending.', 'fluent-cart'),
606 + 'recipient' => 'customer',
607 + 'smartcode_groups' => [],
608 + 'template_path' => 'order.reminder.renewal_overdue.final.customer',
609 + 'is_async' => false,
610 + 'settings' => [
611 + 'active' => 'yes',
612 + 'subject' => __('Final Notice: Payment Overdue for Renewal #{{order.order_ref}}', 'fluent-cart'),
613 + 'is_default_body' => 'yes',
614 + 'email_body' => '',
615 + ]
616 + ],
550 617 'subscription_trial_end_reminder_admin' => [
551 618 'event' => 'subscription_trial_end_reminder',
552 619 'group' => 'scheduler',
553 620 'group_label' => __('Scheduler / Reminder Actions', 'fluent-cart'),
@@ -581,10 +648,123 @@
581 648 'is_default_body' => 'yes',
582 649 'email_body' => '',
583 650 ]
584 651 ],
652 + 'review_submitted_admin' => [
653 + 'event' => 'review_created',
654 + 'group' => 'review',
655 + 'group_label' => __('Review Actions', 'fluent-cart'),
656 + 'title' => __('Send mail to admin when a new review is submitted', 'fluent-cart'),
657 + 'description' => __('Email admin when a customer submits a new review.', 'fluent-cart'),
658 + 'recipient' => 'admin',
659 + 'smartcode_groups' => [],
660 + 'template_path' => 'review.submitted.admin',
661 + 'is_async' => false,
662 + 'pre_header' => __('A new product review has been submitted.', 'fluent-cart'),
663 + 'settings' => [
664 + 'active' => 'yes',
665 + 'subject' => __('New Review Submitted', 'fluent-cart'),
666 + 'is_default_body' => 'yes',
667 + 'email_body' => '',
668 + ]
669 + ],
670 + 'review_approved_customer' => [
671 + // The settled hook, not the transition: fired from a queued
672 + // job once the review has been re-read and is still approved,
673 + // the way order_paid_done is to order_paid. A bulk approve is
674 + // fifty of these, and none of them is sent inside that request.
675 + 'event' => 'review_approved_done',
676 + 'group' => 'review',
677 + 'group_label' => __('Review Actions', 'fluent-cart'),
678 + 'title' => __('Send mail to the reviewer when their review is approved', 'fluent-cart'),
679 + 'description' => __('Email the customer who wrote a review once it is approved and visible on the product page.', 'fluent-cart'),
680 + 'recipient' => 'customer',
681 + // Declared, because the customer recipient resolves through an
682 + // order and a review has none. The resolver behind this code is
683 + // the one every review notification uses.
684 + 'to' => '{{review.recipient_email}}',
685 + 'smartcode_groups' => [],
686 + 'template_path' => 'review.approved.customer',
687 + 'is_async' => false,
688 + 'pre_header' => __('Your review is now live.', 'fluent-cart'),
689 + 'settings' => [
690 + 'active' => 'yes',
691 + 'subject' => __('Your review of {{review.product_title}} is now live', 'fluent-cart'),
692 + 'is_default_body' => 'yes',
693 + 'email_body' => '',
694 + ]
695 + ],
696 + 'review_replied_customer' => [
697 + // Fired from a queued job once the reply and the review it
698 + // answers have both been re-read and are still published.
699 + 'event' => 'review_replied_done',
700 + 'group' => 'review',
701 + 'group_label' => __('Review Actions', 'fluent-cart'),
702 + 'title' => __('Send mail to the reviewer when the store replies to their review', 'fluent-cart'),
703 + 'description' => __('Email the customer who wrote a review when the store posts a reply to it.', 'fluent-cart'),
704 + 'recipient' => 'customer',
705 + // The review's author, resolved the way every review
706 + // notification resolves it — {{review.*}} is the review being
707 + // answered, not the reply.
708 + 'to' => '{{review.recipient_email}}',
709 + 'smartcode_groups' => [],
710 + 'template_path' => 'review.replied.customer',
711 + 'is_async' => false,
712 + 'pre_header' => __('The store has replied to your review.', 'fluent-cart'),
713 + 'settings' => [
714 + 'active' => 'yes',
715 + 'subject' => __('{{settings.store_name}} replied to your review of {{review.product_title}}', 'fluent-cart'),
716 + 'is_default_body' => 'yes',
717 + 'email_body' => '',
718 + ]
719 + ],
585 720 ];
586 721
722 + }
723 +
724 + /**
725 + * The names of the notifications that would send for an event — the same
726 + * gate getNotificationsOfEvent() applies, without rendering a body.
727 + *
728 + * For a caller that only needs to know whether, and which, before it
729 + * commits to something — a once-only lease, say — and will render at
730 + * send time through mailByEmailName(). Rendering here as well would draw
731 + * every template twice per send.
732 + *
733 + * Kept in step with getNotificationsOfEvent(): the four conditions below
734 + * are that method's, in the same order.
735 + *
736 + * @param string $event
737 + * @return string[] notification names, in registry order
738 + */
739 + public static function activeNotificationNamesOfEvent($event): array
740 + {
741 + $mailingSettings = static::getSettings();
742 + $names = [];
743 +
744 + foreach (static::getNotifications() as $key => $notification) {
745 + if (Arr::get($notification, 'event') !== $event) {
746 + continue;
747 + }
748 +
749 + $settings = Arr::get($notification, 'settings');
750 + if (!in_array($notification['event'], ['order_placed_offline', 'renewal_reminder_overdue']) && Arr::get($settings, 'active') !== 'yes') {
751 + continue;
752 + }
753 +
754 + $recipient = Arr::get($notification, 'recipient');
755 + if (!Arr::get($notification, 'to') && !in_array($recipient, ['admin', 'customer', 'user', 'subscriber'])) {
756 + continue;
757 + }
758 +
759 + if (empty(static::resolveRecipientTemplate($notification, $mailingSettings))) {
760 + continue;
761 + }
762 +
763 + $names[] = (string) $key;
764 + }
765 +
766 + return $names;
587 767 }
588 768
589 769 public static function getNotificationsOfEvent($event, $viewData): array
590 770 {