PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.6
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.6
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 1.3.20 1.3.19 All 49 releases
← All changes | app/Hooks/Handlers/ReminderHandler.php +77 -3 1.3.21 → 1.6.6 View file →
@@ -3,9 +3,9 @@
3 3 namespace FluentCart\App\Hooks\Handlers;
4 4
5 5 use FluentCart\App\Models\Order;
6 6 use FluentCart\App\Models\Subscription;
7 -use FluentCart\App\Services\Reminders\InvoiceReminderService;
7 +use FluentCart\App\Services\Reminders\RenewalReminderService;
8 8 use FluentCart\App\Services\Reminders\ReminderService;
9 9 use FluentCart\App\Services\Reminders\SubscriptionReminderService;
10 10 use FluentCart\Framework\Support\Arr;
11 11
@@ -16,8 +16,9 @@
16 16 add_action('fluent_cart/scheduler/hourly_tasks', [$this, 'scan'], 40);
17 17
18 18 add_action(SubscriptionReminderService::RENEWAL_ASYNC_HOOK, [$this, 'sendSubscriptionRenewalReminder'], 10, 3);
19 19 add_action(SubscriptionReminderService::TRIAL_ASYNC_HOOK, [$this, 'sendSubscriptionTrialReminder'], 10, 3);
20 + add_action(RenewalReminderService::ASYNC_HOOK, [$this, 'sendRenewalReminder'], 10, 3);
20 21
21 22 add_filter('fluent_cart/store_settings/values', [$this, 'addDefaultStoreSettings'], 10, 2);
22 23 add_filter('fluent_cart/store_settings/fields', [$this, 'addStoreSettingFields'], 10, 2);
23 24 add_filter('fluent_cart/store_settings/sanitizer', [$this, 'addStoreSettingSanitizers']);
@@ -26,8 +27,14 @@
26 27 add_action('fluent_cart/order_refunded', [$this, 'clearOrderReminderState'], 10, 1);
27 28
28 29 add_action('fluent_cart/payments/subscription_canceled', [$this, 'clearSubscriptionReminderState'], 10, 1);
29 30 add_action('fluent_cart/payments/subscription_expired', [$this, 'clearSubscriptionReminderState'], 10, 1);
31 +
32 + // Also listen on the native events so reminder state clears on the paths the
33 + // raw status bus misses (cancel button, model cancel, cron expiry). clearState
34 + // is idempotent, so the edit path clearing twice is harmless.
35 + add_action('fluent_cart/subscription_canceled', [$this, 'clearSubscriptionReminderState'], 10, 1);
36 + add_action('fluent_cart/subscription_expired_validity', [$this, 'clearSubscriptionReminderState'], 10, 1);
30 37 }
31 38
32 39 public function scan(): void
33 40 {
@@ -43,8 +50,13 @@
43 50 {
44 51 (new SubscriptionReminderService())->sendTrial($subscriptionId, $stage, $cycleKey);
45 52 }
46 53
54 + public function sendRenewalReminder($orderId, $stage, $cycleKey): void
55 + {
56 + (new RenewalReminderService())->send($orderId, $stage, $cycleKey);
57 + }
58 +
47 59 public function addDefaultStoreSettings($defaults): array
48 60 {
49 61 if (!is_array($defaults)) {
50 62 $defaults = [];
@@ -64,8 +76,11 @@
64 76 'quarterly_renewal_reminders_enabled' => 'no',
65 77 'quarterly_renewal_reminder_days' => '14',
66 78 'half_yearly_renewal_reminders_enabled' => 'no',
67 79 'half_yearly_renewal_reminder_days' => '21',
80 + // Invoice reminders for manual subscriptions
81 + 'renewal_reminders_enabled' => 'no',
82 + 'renewal_reminder_overdue_days' => '1,3,7',
68 83 ]);
69 84 }
70 85
71 86 public function addStoreSettingFields($fields): array
@@ -124,9 +139,9 @@
124 139
125 140 'email_notice' => [
126 141 'conditions' => $enabledCondition,
127 142 'type' => 'html',
128 - 'value' => '<div class="fc_reminder_email_notice" style="background: #f0f6ff; border: 1px solid #d0e2ff; border-radius: 6px; padding: 10px 14px; font-size: 13px; color: #1e3a5f;">'
143 + 'value' => '<div class="fct-alert">'
129 144 . sprintf(
130 145 /* translators: %s is the opening and closing anchor tag */
131 146 __('Reminder emails must also be enabled in %1$sEmail Notification Settings%2$s under "Scheduler / Reminder Actions" to be delivered.', 'fluent-cart'),
132 147 '<a href="#/settings/email_notifications" style="color: #017EF3; text-decoration: underline;">',
@@ -269,8 +284,63 @@
269 284 ],
270 285 ],
271 286 ],
272 287 ],
288 +
289 + // ── Invoice Reminders Group ──
290 + 'invoice_hr' => [
291 + 'conditions' => $enabledCondition,
292 + 'type' => 'html',
293 + 'value' => '<hr class="settings-divider">'
294 + ],
295 + 'invoice_group_label' => [
296 + 'conditions' => $enabledCondition,
297 + 'type' => 'html',
298 + 'wrapperClass' => 'mb-4',
299 + 'value' => '<span class="setting-label" style="font-size: 15px;">' . __('Invoice Reminders', 'fluent-cart') . '</span>
300 + <div class="form-note">' . __('Send overdue reminders for unpaid renewal orders on manual subscriptions.', 'fluent-cart') . '</div>'
301 + ],
302 + 'invoice_inner_hr' => [
303 + 'conditions' => $enabledCondition,
304 + 'type' => 'html',
305 + 'value' => '<hr class="settings-divider">'
306 + ],
307 + 'invoice_grid' => [
308 + 'conditions' => $enabledCondition,
309 + 'type' => 'grid',
310 + 'columns' => [
311 + 'default' => 1,
312 + 'md' => 3
313 + ],
314 + 'disable_nesting' => true,
315 + 'schema' => [
316 + 'invoice_label' => [
317 + 'type' => 'html',
318 + 'value' => '<span class="setting-label">' . __('Overdue Invoice Reminders', 'fluent-cart') . '</span>
319 + <div class="form-note">' . __('Remind customers about unpaid invoices after the due date.', 'fluent-cart') . '</div>'
320 + ],
321 + 'invoice_input_grid' => [
322 + 'type' => 'grid',
323 + 'columns' => ['default' => 1, 'md' => 1],
324 + 'disable_nesting' => true,
325 + 'class' => 'col-span-2',
326 + 'schema' => [
327 + 'renewal_reminders_enabled' => [
328 + 'label' => __('Enable', 'fluent-cart'),
329 + 'type' => 'checkbox',
330 + 'value' => 'yes',
331 + ],
332 + 'renewal_reminder_overdue_days' => [
333 + 'label' => false,
334 + 'type' => 'input',
335 + 'value' => '1,3,7',
336 + 'note' => __('Days after due date to send overdue reminders. Comma-separated (e.g. 1,3,7). Default: 1,3,7', 'fluent-cart'),
337 + 'conditions' => [['key' => 'renewal_reminders_enabled', 'operator' => '==', 'value' => 'yes']],
338 + ],
339 + ],
340 + ],
341 + ],
342 + ],
273 343 ],
274 344 ];
275 345
276 346 Arr::set($fields, $tabsPath, $tabs);
@@ -300,8 +370,12 @@
300 370 $sanitizers['quarterly_renewal_reminder_days'] = 'intval';
301 371 $sanitizers['half_yearly_renewal_reminders_enabled'] = 'sanitize_text_field';
302 372 $sanitizers['half_yearly_renewal_reminder_days'] = 'intval';
303 373
374 + // Invoice reminder sanitizers
375 + $sanitizers['renewal_reminders_enabled'] = 'sanitize_text_field';
376 + $sanitizers['renewal_reminder_overdue_days'] = 'sanitize_text_field';
377 +
304 378 return $sanitizers;
305 379 }
306 380
307 381 public function clearOrderReminderState($data): void
@@ -311,9 +385,9 @@
311 385 if (!$order instanceof Order) {
312 386 return;
313 387 }
314 388
315 - (new InvoiceReminderService())->clearState($order);
389 + (new RenewalReminderService())->clearState($order);
316 390 } catch (\Throwable $e) {
317 391 fluent_cart_error_log('Reminder state clear error', $e->getMessage());
318 392 }
319 393 }