diff --git a/admin-spa/src/routes/Settings/Notifications.tsx b/admin-spa/src/routes/Settings/Notifications.tsx
index 69febdb..ed52590 100644
--- a/admin-spa/src/routes/Settings/Notifications.tsx
+++ b/admin-spa/src/routes/Settings/Notifications.tsx
@@ -1,280 +1,38 @@
import React, { useState } from 'react';
-import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
-import { api } from '@/lib/api';
import { SettingsLayout } from './components/SettingsLayout';
-import { SettingsCard } from './components/SettingsCard';
-import { Switch } from '@/components/ui/switch';
-import { Button } from '@/components/ui/button';
-import { Badge } from '@/components/ui/badge';
-import { ExternalLink, RefreshCw, Mail, MessageCircle, Send, Bell } from 'lucide-react';
-import { toast } from 'sonner';
+import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { __ } from '@/lib/i18n';
+import NotificationEvents from './Notifications/Events';
+import NotificationChannels from './Notifications/Channels';
+import NotificationTemplates from './Notifications/Templates';
export default function NotificationsSettings() {
- const queryClient = useQueryClient();
- const [activeTab, setActiveTab] = useState<'channels' | 'events'>('channels');
-
- // Fetch notification channels
- const { data: channels, isLoading: channelsLoading } = useQuery({
- queryKey: ['notification-channels'],
- queryFn: () => api.get('/notifications/channels'),
- });
-
- // Fetch notification events
- const { data: events, isLoading: eventsLoading } = useQuery({
- queryKey: ['notification-events'],
- queryFn: () => api.get('/notifications/events'),
- });
-
- // Fetch notification settings
- const { data: settings, isLoading: settingsLoading } = useQuery({
- queryKey: ['notification-settings'],
- queryFn: () => api.get('/notifications/settings'),
- });
-
- // Update settings mutation
- const updateMutation = useMutation({
- mutationFn: async (newSettings: any) => {
- return api.post('/notifications/settings', newSettings);
- },
- onSuccess: () => {
- queryClient.invalidateQueries({ queryKey: ['notification-settings'] });
- queryClient.invalidateQueries({ queryKey: ['notification-events'] });
- toast.success(__('Notification settings updated'));
- },
- onError: (error: any) => {
- toast.error(error?.message || __('Failed to update settings'));
- },
- });
-
- const toggleEventChannel = (eventId: string, channelId: string, enabled: boolean) => {
- const newSettings = { ...settings };
- if (!newSettings.events) newSettings.events = {};
- if (!newSettings.events[eventId]) newSettings.events[eventId] = { enabled: true, channels: [], recipients: {} };
-
- const channels = newSettings.events[eventId].channels || [];
- if (enabled) {
- if (!channels.includes(channelId)) {
- newSettings.events[eventId].channels = [...channels, channelId];
- }
- } else {
- newSettings.events[eventId].channels = channels.filter((c: string) => c !== channelId);
- }
-
- updateMutation.mutate(newSettings);
- };
-
- const isLoading = channelsLoading || eventsLoading || settingsLoading;
-
- if (isLoading) {
- return (
-
-
-
-
-
- );
- }
-
- const getChannelIcon = (channelId: string) => {
- switch (channelId) {
- case 'email': return ;
- case 'whatsapp': return ;
- case 'telegram': return ;
- default: return ;
- }
- };
+ const [activeTab, setActiveTab] = useState('events');
return (
-
- {/* Notification Channels */}
-
-
- {channels?.map((channel: any) => (
-
-
-
- {getChannelIcon(channel.id)}
-
-
-
-
{channel.label}
- {channel.builtin && (
- {__('Built-in')}
- )}
- {channel.addon && (
- {__('Addon')}
- )}
-
- {channel.addon && (
-
- {__('Provided by')} {channel.addon}
-
- )}
-
-
-
- {channel.enabled ? __('Active') : __('Inactive')}
-
-
- ))}
-
-
-
- 💡 {__('Want more channels like WhatsApp, Telegram, or SMS? Install notification addons to extend your notification capabilities.')}
-
-
-
-
+
+
+ {__('Events')}
+ {__('Channels')}
+ {__('Templates')}
+
- {/* Order Notifications */}
- {events?.orders && events.orders.length > 0 && (
-
-
- {events.orders.map((event: any) => (
-
-
-
-
{event.label}
-
{event.description}
-
-
-
- {channels?.map((channel: any) => {
- const isEnabled = event.channels?.includes(channel.id);
- return (
- toggleEventChannel(event.id, channel.id, !isEnabled)}
- disabled={!channel.enabled || updateMutation.isPending}
- className="text-xs"
- >
- {getChannelIcon(channel.id)}
- {channel.label}
-
- );
- })}
-
-
- ))}
-
-
- )}
+
+
+
- {/* Product Notifications */}
- {events?.products && events.products.length > 0 && (
-
-
- {events.products.map((event: any) => (
-
-
-
-
{event.label}
-
{event.description}
-
-
-
- {channels?.map((channel: any) => {
- const isEnabled = event.channels?.includes(channel.id);
- return (
- toggleEventChannel(event.id, channel.id, !isEnabled)}
- disabled={!channel.enabled || updateMutation.isPending}
- className="text-xs"
- >
- {getChannelIcon(channel.id)}
- {channel.label}
-
- );
- })}
-
-
- ))}
-
-
- )}
+
+
+
- {/* Customer Notifications */}
- {events?.customers && events.customers.length > 0 && (
-
-
- {events.customers.map((event: any) => (
-
-
-
-
{event.label}
-
{event.description}
-
-
-
- {channels?.map((channel: any) => {
- const isEnabled = event.channels?.includes(channel.id);
- return (
- toggleEventChannel(event.id, channel.id, !isEnabled)}
- disabled={!channel.enabled || updateMutation.isPending}
- className="text-xs"
- >
- {getChannelIcon(channel.id)}
- {channel.label}
-
- );
- })}
-
-
- ))}
-
-
- )}
-
- {/* WooCommerce Email Settings Link */}
-
-
-
- {__('Email notifications are powered by WooCommerce. For advanced customization like templates, subject lines, and sender details, use the WooCommerce email settings.')}
-
-
window.open(`${(window as any).WNW_CONFIG?.wpAdminUrl || '/wp-admin'}/admin.php?page=wc-settings&tab=email`, '_blank')}
- >
-
- {__('Open WooCommerce Email Settings')}
-
-
-
-
-
+
+
+
+
);
}
diff --git a/admin-spa/src/routes/Settings/Notifications/Channels.tsx b/admin-spa/src/routes/Settings/Notifications/Channels.tsx
new file mode 100644
index 0000000..97a6597
--- /dev/null
+++ b/admin-spa/src/routes/Settings/Notifications/Channels.tsx
@@ -0,0 +1,215 @@
+import React from 'react';
+import { useQuery } from '@tanstack/react-query';
+import { api } from '@/lib/api';
+import { SettingsCard } from '../components/SettingsCard';
+import { Badge } from '@/components/ui/badge';
+import { Button } from '@/components/ui/button';
+import { RefreshCw, Mail, MessageCircle, Send, Bell, ExternalLink, Settings } from 'lucide-react';
+import { __ } from '@/lib/i18n';
+
+interface NotificationChannel {
+ id: string;
+ label: string;
+ icon: string;
+ enabled: boolean;
+ builtin?: boolean;
+ addon?: string;
+}
+
+export default function NotificationChannels() {
+ // Fetch channels
+ const { data: channels, isLoading } = useQuery({
+ queryKey: ['notification-channels'],
+ queryFn: () => api.get('/notifications/channels'),
+ });
+
+ const getChannelIcon = (channelId: string) => {
+ switch (channelId) {
+ case 'email':
+ return ;
+ case 'whatsapp':
+ return ;
+ case 'telegram':
+ return ;
+ default:
+ return ;
+ }
+ };
+
+ if (isLoading) {
+ return (
+
+
+
+ );
+ }
+
+ const builtinChannels = channels?.filter((c: NotificationChannel) => c.builtin) || [];
+ const addonChannels = channels?.filter((c: NotificationChannel) => !c.builtin) || [];
+
+ return (
+
+ {/* Info Card */}
+
+
+
+ {__(
+ 'Channels are the different ways notifications can be sent. Email is built-in and always available. Install addons to enable additional channels like WhatsApp, Telegram, SMS, and more.'
+ )}
+
+
+
+
+ {/* Built-in Channels */}
+
+
+ {builtinChannels.map((channel: NotificationChannel) => (
+
+
+
{getChannelIcon(channel.id)}
+
+
+
{channel.label}
+
+ {__('Built-in')}
+
+
+ {channel.enabled ? __('Active') : __('Inactive')}
+
+
+
+ {channel.id === 'email' &&
+ __('Email notifications powered by WooCommerce. Configure templates and SMTP settings.')}
+
+
+
+ {channel.id === 'email' && (
+
+ window.open(
+ `${(window as any).WNW_CONFIG?.wpAdminUrl || '/wp-admin'}/admin.php?page=wc-settings&tab=email`,
+ '_blank'
+ )
+ }
+ >
+
+ {__('Configure')}
+
+ )}
+
+ ))}
+
+
+
+ {/* Addon Channels */}
+ {addonChannels.length > 0 ? (
+
+
+ {addonChannels.map((channel: NotificationChannel) => (
+
+
+
{getChannelIcon(channel.id)}
+
+
+
{channel.label}
+
+ {__('Addon')}
+
+
+ {channel.enabled ? __('Active') : __('Inactive')}
+
+
+
+ {__('Provided by')} {channel.addon}
+
+
+
+
+
+ {__('Configure')}
+
+
+ ))}
+
+
+ ) : (
+
+
+
+ {__(
+ 'Install notification addons to send notifications via WhatsApp, Telegram, SMS, Push notifications, and more.'
+ )}
+
+
+
+ {/* Example addon cards */}
+
+
+
+
{__('WhatsApp Notifications')}
+
+
+ {__('Send order updates and notifications via WhatsApp Business API')}
+
+
+
+ {__('View Addon')}
+
+
+
+
+
+
+
{__('Telegram Notifications')}
+
+
+ {__('Get instant notifications in your Telegram channel or group')}
+
+
+
+ {__('View Addon')}
+
+
+
+
+
+
+
{__('SMS Notifications')}
+
+
+ {__('Send SMS notifications via Twilio, Nexmo, or other providers')}
+
+
+
+ {__('View Addon')}
+
+
+
+
+
+
+
{__('Push Notifications')}
+
+
+ {__('Send browser push notifications to customers and admins')}
+
+
+
+ {__('View Addon')}
+
+
+
+
+
+ )}
+
+ );
+}
diff --git a/admin-spa/src/routes/Settings/Notifications/Events.tsx b/admin-spa/src/routes/Settings/Notifications/Events.tsx
new file mode 100644
index 0000000..5fbcf6f
--- /dev/null
+++ b/admin-spa/src/routes/Settings/Notifications/Events.tsx
@@ -0,0 +1,312 @@
+import React from 'react';
+import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
+import { api } from '@/lib/api';
+import { SettingsCard } from '../components/SettingsCard';
+import { Switch } from '@/components/ui/switch';
+import { Button } from '@/components/ui/button';
+import { Badge } from '@/components/ui/badge';
+import { RefreshCw, Mail, MessageCircle, Send, Bell } from 'lucide-react';
+import { toast } from 'sonner';
+import { __ } from '@/lib/i18n';
+
+interface NotificationEvent {
+ id: string;
+ label: string;
+ description: string;
+ category: string;
+ enabled: boolean;
+ channels: {
+ [channelId: string]: {
+ enabled: boolean;
+ recipient: 'admin' | 'customer' | 'both';
+ };
+ };
+}
+
+interface NotificationChannel {
+ id: string;
+ label: string;
+ icon: string;
+ enabled: boolean;
+ builtin?: boolean;
+ addon?: string;
+}
+
+export default function NotificationEvents() {
+ const queryClient = useQueryClient();
+
+ // Fetch events
+ const { data: eventsData, isLoading: eventsLoading } = useQuery({
+ queryKey: ['notification-events'],
+ queryFn: () => api.get('/notifications/events'),
+ });
+
+ // Fetch channels
+ const { data: channels, isLoading: channelsLoading } = useQuery({
+ queryKey: ['notification-channels'],
+ queryFn: () => api.get('/notifications/channels'),
+ });
+
+ // Update event mutation
+ const updateMutation = useMutation({
+ mutationFn: async ({ eventId, channelId, enabled, recipient }: any) => {
+ return api.post('/notifications/events/update', {
+ eventId,
+ channelId,
+ enabled,
+ recipient,
+ });
+ },
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: ['notification-events'] });
+ toast.success(__('Event settings updated'));
+ },
+ onError: (error: any) => {
+ toast.error(error?.message || __('Failed to update event'));
+ },
+ });
+
+ const getChannelIcon = (channelId: string) => {
+ switch (channelId) {
+ case 'email':
+ return ;
+ case 'whatsapp':
+ return ;
+ case 'telegram':
+ return ;
+ default:
+ return ;
+ }
+ };
+
+ const toggleChannel = (eventId: string, channelId: string, currentlyEnabled: boolean) => {
+ updateMutation.mutate({
+ eventId,
+ channelId,
+ enabled: !currentlyEnabled,
+ recipient: 'admin', // Default recipient
+ });
+ };
+
+ if (eventsLoading || channelsLoading) {
+ return (
+
+
+
+ );
+ }
+
+ const orderEvents = eventsData?.orders || [];
+ const productEvents = eventsData?.products || [];
+ const customerEvents = eventsData?.customers || [];
+
+ return (
+
+ {/* Info Card */}
+
+
+
+ {__(
+ 'Choose which notification channels (Email, WhatsApp, Telegram, etc.) should be used for each event. Enable multiple channels to send notifications through different mediums.'
+ )}
+
+
+
+ 💡 {__('Tip: Email is always available. Install addons to enable WhatsApp, Telegram, SMS, and other channels.')}
+
+
+
+
+
+ {/* Order Events */}
+ {orderEvents.length > 0 && (
+
+
+ {orderEvents.map((event: NotificationEvent) => (
+
+
+
+
{event.label}
+
{event.description}
+
+
+
+
+ {/* Channel Selection */}
+
+ {channels?.map((channel: NotificationChannel) => {
+ const channelEnabled = event.channels?.[channel.id]?.enabled || false;
+ const recipient = event.channels?.[channel.id]?.recipient || 'admin';
+
+ return (
+
+
+
+ {getChannelIcon(channel.id)}
+
+
+
+ {channel.label}
+ {channel.builtin && (
+
+ {__('Built-in')}
+
+ )}
+
+ {channelEnabled && (
+
+ {__('Send to')}: {recipient === 'admin' ? __('Admin') : recipient === 'customer' ? __('Customer') : __('Both')}
+
+ )}
+
+
+
toggleChannel(event.id, channel.id, channelEnabled)}
+ disabled={!channel.enabled || updateMutation.isPending}
+ />
+
+ );
+ })}
+
+
+ ))}
+
+
+ )}
+
+ {/* Product Events */}
+ {productEvents.length > 0 && (
+
+
+ {productEvents.map((event: NotificationEvent) => (
+
+
+
+
{event.label}
+
{event.description}
+
+
+
+
+
+ {channels?.map((channel: NotificationChannel) => {
+ const channelEnabled = event.channels?.[channel.id]?.enabled || false;
+ const recipient = event.channels?.[channel.id]?.recipient || 'admin';
+
+ return (
+
+
+
+ {getChannelIcon(channel.id)}
+
+
+
+ {channel.label}
+ {channel.builtin && (
+
+ {__('Built-in')}
+
+ )}
+
+ {channelEnabled && (
+
+ {__('Send to')}: {recipient === 'admin' ? __('Admin') : recipient === 'customer' ? __('Customer') : __('Both')}
+
+ )}
+
+
+
toggleChannel(event.id, channel.id, channelEnabled)}
+ disabled={!channel.enabled || updateMutation.isPending}
+ />
+
+ );
+ })}
+
+
+ ))}
+
+
+ )}
+
+ {/* Customer Events */}
+ {customerEvents.length > 0 && (
+
+
+ {customerEvents.map((event: NotificationEvent) => (
+
+
+
+
{event.label}
+
{event.description}
+
+
+
+
+
+ {channels?.map((channel: NotificationChannel) => {
+ const channelEnabled = event.channels?.[channel.id]?.enabled || false;
+ const recipient = event.channels?.[channel.id]?.recipient || 'admin';
+
+ return (
+
+
+
+ {getChannelIcon(channel.id)}
+
+
+
+ {channel.label}
+ {channel.builtin && (
+
+ {__('Built-in')}
+
+ )}
+
+ {channelEnabled && (
+
+ {__('Send to')}: {recipient === 'admin' ? __('Admin') : recipient === 'customer' ? __('Customer') : __('Both')}
+
+ )}
+
+
+
toggleChannel(event.id, channel.id, channelEnabled)}
+ disabled={!channel.enabled || updateMutation.isPending}
+ />
+
+ );
+ })}
+
+
+ ))}
+
+
+ )}
+
+ );
+}
diff --git a/admin-spa/src/routes/Settings/Notifications/Templates.tsx b/admin-spa/src/routes/Settings/Notifications/Templates.tsx
new file mode 100644
index 0000000..dd4b54b
--- /dev/null
+++ b/admin-spa/src/routes/Settings/Notifications/Templates.tsx
@@ -0,0 +1,225 @@
+import React from 'react';
+import { useQuery } from '@tanstack/react-query';
+import { api } from '@/lib/api';
+import { SettingsCard } from '../components/SettingsCard';
+import { Button } from '@/components/ui/button';
+import { Badge } from '@/components/ui/badge';
+import { RefreshCw, Mail, MessageCircle, Send, Bell, ExternalLink, Edit, Eye } from 'lucide-react';
+import { __ } from '@/lib/i18n';
+
+interface NotificationChannel {
+ id: string;
+ label: string;
+ icon: string;
+ enabled: boolean;
+ builtin?: boolean;
+ addon?: string;
+}
+
+export default function NotificationTemplates() {
+ // Fetch channels
+ const { data: channels, isLoading } = useQuery({
+ queryKey: ['notification-channels'],
+ queryFn: () => api.get('/notifications/channels'),
+ });
+
+ const getChannelIcon = (channelId: string) => {
+ switch (channelId) {
+ case 'email':
+ return ;
+ case 'whatsapp':
+ return ;
+ case 'telegram':
+ return ;
+ default:
+ return ;
+ }
+ };
+
+ if (isLoading) {
+ return (
+
+
+
+ );
+ }
+
+ const enabledChannels = channels?.filter((c: NotificationChannel) => c.enabled) || [];
+
+ return (
+
+ {/* Info Card */}
+
+
+
+ {__(
+ 'Templates define the content and format of notifications sent through each channel. Customize the message, subject, and variables for each notification type.'
+ )}
+
+
+
+ 💡 {__('Tip: Use variables like {customer_name}, {order_number}, and {order_total} to personalize your notifications.')}
+
+
+
+
+
+ {/* Email Templates */}
+
+
+
+
+
+
+
+
+
+
{__('Email Templates')}
+
+ {__('Built-in')}
+
+
+
+ {__('Email templates are managed by WooCommerce. Customize subject lines, headers, and content.')}
+
+
+
+
+ window.open(
+ `${(window as any).WNW_CONFIG?.wpAdminUrl || '/wp-admin'}/admin.php?page=wc-settings&tab=email`,
+ '_blank'
+ )
+ }
+ >
+
+ {__('Edit Templates')}
+
+
+
+
+
{__('Available Email Templates')}
+
+ • {__('New Order (Admin)')}
+ • {__('Order Processing (Customer)')}
+ • {__('Order Completed (Customer)')}
+ • {__('Order Cancelled')}
+ • {__('Order Refunded')}
+ • {__('Customer Note')}
+ • {__('Low Stock Alert')}
+ • {__('Out of Stock Alert')}
+
+
+
+
+
+ {/* Addon Channel Templates */}
+ {enabledChannels.filter((c: NotificationChannel) => !c.builtin).length > 0 ? (
+
+
+ {enabledChannels
+ .filter((c: NotificationChannel) => !c.builtin)
+ .map((channel: NotificationChannel) => (
+
+
+
{getChannelIcon(channel.id)}
+
+
+
{channel.label} {__('Templates')}
+
+ {__('Addon')}
+
+
+
+ {__('Customize message templates for')} {channel.label} {__('notifications')}
+
+
+
+
+
+
+ {__('Preview')}
+
+
+
+ {__('Edit')}
+
+
+
+ ))}
+
+
+ ) : (
+
+
+
+
+ {__(
+ 'Install notification addons like WhatsApp, Telegram, or SMS to customize their message templates.'
+ )}
+
+
+
+ {__('Browse Addons')}
+
+
+
+ )}
+
+ {/* Template Variables Reference */}
+
+
+
+
{__('Order Variables')}
+
+ {'{order_number}'}
+ {'{order_total}'}
+ {'{order_status}'}
+ {'{order_date}'}
+ {'{payment_method}'}
+ {'{shipping_method}'}
+
+
+
+
+
{__('Customer Variables')}
+
+ {'{customer_name}'}
+ {'{customer_email}'}
+ {'{customer_phone}'}
+ {'{billing_address}'}
+ {'{shipping_address}'}
+
+
+
+
+
{__('Store Variables')}
+
+ {'{store_name}'}
+ {'{store_url}'}
+ {'{store_email}'}
+ {'{store_phone}'}
+
+
+
+
+
+ );
+}
diff --git a/includes/Api/NotificationsController.php b/includes/Api/NotificationsController.php
index 6953ed7..d3e9169 100644
--- a/includes/Api/NotificationsController.php
+++ b/includes/Api/NotificationsController.php
@@ -2,7 +2,7 @@
/**
* Notifications REST API Controller
*
- * Handles notification settings API endpoints.
+ * Bridge to WooCommerce emails + addon channel framework.
*
* @package WooNooW\Api
*/
@@ -12,8 +12,6 @@ namespace WooNooW\Api;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;
-use WooNooW\Core\Notifications\NotificationManager;
-use WooNooW\Core\Notifications\NotificationSettingsProvider;
class NotificationsController {
@@ -49,20 +47,11 @@ class NotificationsController {
],
]);
- // GET /woonoow/v1/notifications/settings
- register_rest_route($this->namespace, '/' . $this->rest_base . '/settings', [
- [
- 'methods' => 'GET',
- 'callback' => [$this, 'get_settings'],
- 'permission_callback' => [$this, 'check_permission'],
- ],
- ]);
-
- // POST /woonoow/v1/notifications/settings
- register_rest_route($this->namespace, '/' . $this->rest_base . '/settings', [
+ // POST /woonoow/v1/notifications/events/update
+ register_rest_route($this->namespace, '/' . $this->rest_base . '/events/update', [
[
'methods' => 'POST',
- 'callback' => [$this, 'update_settings'],
+ 'callback' => [$this, 'update_event'],
'permission_callback' => [$this, 'check_permission'],
],
]);
@@ -75,17 +64,20 @@ class NotificationsController {
* @return WP_REST_Response
*/
public function get_channels(WP_REST_Request $request) {
- $channels = NotificationManager::get_channels();
+ $channels = [
+ [
+ 'id' => 'email',
+ 'label' => __('Email', 'woonoow'),
+ 'icon' => 'mail',
+ 'enabled' => true,
+ 'builtin' => true,
+ ],
+ ];
- // Add enabled status from settings
- $settings = NotificationSettingsProvider::get_settings();
- $channel_settings = $settings['channels'] ?? [];
+ // Allow addons to register their channels
+ $channels = apply_filters('woonoow_notification_channels', $channels);
- foreach ($channels as $id => &$channel) {
- $channel['enabled'] = $channel_settings[$id]['enabled'] ?? $channel['builtin'];
- }
-
- return new WP_REST_Response(array_values($channels), 200);
+ return new WP_REST_Response($channels, 200);
}
/**
@@ -95,78 +87,148 @@ class NotificationsController {
* @return WP_REST_Response
*/
public function get_events(WP_REST_Request $request) {
- $events = NotificationManager::get_events();
- $settings = NotificationSettingsProvider::get_settings();
- $event_settings = $settings['events'] ?? [];
+ // Get saved settings
+ $settings = get_option('woonoow_notification_settings', []);
- // Merge event data with settings
- foreach ($events as $id => &$event) {
- $event_config = $event_settings[$id] ?? [];
- $event['enabled'] = $event_config['enabled'] ?? true;
- $event['channels'] = $event_config['channels'] ?? ['email'];
- $event['recipients'] = $event_config['recipients'] ?? ['email' => 'admin'];
- }
-
- // Group by category
- $grouped = [
- 'orders' => [],
- 'products' => [],
- 'customers' => [],
+ // Define default events (maps to WooCommerce emails)
+ $events = [
+ 'orders' => [
+ [
+ 'id' => 'order_placed',
+ 'label' => __('Order Placed', 'woonoow'),
+ 'description' => __('When a new order is placed', 'woonoow'),
+ 'category' => 'orders',
+ 'wc_email' => 'new_order',
+ 'enabled' => true,
+ 'channels' => $settings['order_placed'] ?? ['email' => ['enabled' => true, 'recipient' => 'admin']],
+ ],
+ [
+ 'id' => 'order_processing',
+ 'label' => __('Order Processing', 'woonoow'),
+ 'description' => __('When order status changes to processing', 'woonoow'),
+ 'category' => 'orders',
+ 'wc_email' => 'customer_processing_order',
+ 'enabled' => true,
+ 'channels' => $settings['order_processing'] ?? ['email' => ['enabled' => true, 'recipient' => 'customer']],
+ ],
+ [
+ 'id' => 'order_completed',
+ 'label' => __('Order Completed', 'woonoow'),
+ 'description' => __('When order is marked as completed', 'woonoow'),
+ 'category' => 'orders',
+ 'wc_email' => 'customer_completed_order',
+ 'enabled' => true,
+ 'channels' => $settings['order_completed'] ?? ['email' => ['enabled' => true, 'recipient' => 'customer']],
+ ],
+ [
+ 'id' => 'order_cancelled',
+ 'label' => __('Order Cancelled', 'woonoow'),
+ 'description' => __('When order is cancelled', 'woonoow'),
+ 'category' => 'orders',
+ 'wc_email' => 'cancelled_order',
+ 'enabled' => true,
+ 'channels' => $settings['order_cancelled'] ?? ['email' => ['enabled' => true, 'recipient' => 'admin']],
+ ],
+ [
+ 'id' => 'order_refunded',
+ 'label' => __('Order Refunded', 'woonoow'),
+ 'description' => __('When order is refunded', 'woonoow'),
+ 'category' => 'orders',
+ 'wc_email' => 'customer_refunded_order',
+ 'enabled' => true,
+ 'channels' => $settings['order_refunded'] ?? ['email' => ['enabled' => true, 'recipient' => 'customer']],
+ ],
+ ],
+ 'products' => [
+ [
+ 'id' => 'low_stock',
+ 'label' => __('Low Stock Alert', 'woonoow'),
+ 'description' => __('When product stock is low', 'woonoow'),
+ 'category' => 'products',
+ 'wc_email' => 'low_stock',
+ 'enabled' => true,
+ 'channels' => $settings['low_stock'] ?? ['email' => ['enabled' => true, 'recipient' => 'admin']],
+ ],
+ [
+ 'id' => 'out_of_stock',
+ 'label' => __('Out of Stock Alert', 'woonoow'),
+ 'description' => __('When product is out of stock', 'woonoow'),
+ 'category' => 'products',
+ 'wc_email' => 'no_stock',
+ 'enabled' => true,
+ 'channels' => $settings['out_of_stock'] ?? ['email' => ['enabled' => true, 'recipient' => 'admin']],
+ ],
+ ],
+ 'customers' => [
+ [
+ 'id' => 'new_customer',
+ 'label' => __('New Customer', 'woonoow'),
+ 'description' => __('When a new customer registers', 'woonoow'),
+ 'category' => 'customers',
+ 'wc_email' => 'customer_new_account',
+ 'enabled' => true,
+ 'channels' => $settings['new_customer'] ?? ['email' => ['enabled' => true, 'recipient' => 'customer']],
+ ],
+ [
+ 'id' => 'customer_note',
+ 'label' => __('Customer Note Added', 'woonoow'),
+ 'description' => __('When a note is added to customer order', 'woonoow'),
+ 'category' => 'customers',
+ 'wc_email' => 'customer_note',
+ 'enabled' => true,
+ 'channels' => $settings['customer_note'] ?? ['email' => ['enabled' => true, 'recipient' => 'customer']],
+ ],
+ ],
];
- foreach ($events as $event) {
- $category = $event['category'] ?? 'general';
- if (!isset($grouped[$category])) {
- $grouped[$category] = [];
- }
- $grouped[$category][] = $event;
- }
+ // Allow addons to add custom events
+ $events = apply_filters('woonoow_notification_events', $events);
- return new WP_REST_Response($grouped, 200);
+ return new WP_REST_Response($events, 200);
}
/**
- * Get notification settings
- *
- * @param WP_REST_Request $request Request object
- * @return WP_REST_Response
- */
- public function get_settings(WP_REST_Request $request) {
- $settings = NotificationSettingsProvider::get_settings();
- return new WP_REST_Response($settings, 200);
- }
-
- /**
- * Update notification settings
+ * Update event settings
*
* @param WP_REST_Request $request Request object
* @return WP_REST_Response|WP_Error
*/
- public function update_settings(WP_REST_Request $request) {
- $new_settings = $request->get_json_params();
+ public function update_event(WP_REST_Request $request) {
+ $event_id = $request->get_param('eventId');
+ $channel_id = $request->get_param('channelId');
+ $enabled = $request->get_param('enabled');
+ $recipient = $request->get_param('recipient');
- if (empty($new_settings)) {
+ if (empty($event_id) || empty($channel_id)) {
return new WP_Error(
- 'invalid_settings',
- __('Invalid settings data', 'woonoow'),
+ 'invalid_params',
+ __('Event ID and Channel ID are required', 'woonoow'),
['status' => 400]
);
}
- $updated = NotificationSettingsProvider::update_settings($new_settings);
+ // Get current settings
+ $settings = get_option('woonoow_notification_settings', []);
- if (!$updated) {
- return new WP_Error(
- 'update_failed',
- __('Failed to update notification settings', 'woonoow'),
- ['status' => 500]
- );
+ // Update settings
+ if (!isset($settings[$event_id])) {
+ $settings[$event_id] = [];
}
+ $settings[$event_id][$channel_id] = [
+ 'enabled' => $enabled,
+ 'recipient' => $recipient ?? 'admin',
+ ];
+
+ // Save settings
+ update_option('woonoow_notification_settings', $settings);
+
+ // Fire action for addons to react
+ do_action('woonoow_notification_event_updated', $event_id, $channel_id, $enabled, $recipient);
+
return new WP_REST_Response([
'success' => true,
- 'message' => __('Notification settings updated successfully', 'woonoow'),
- 'settings' => NotificationSettingsProvider::get_settings(),
+ 'message' => __('Event settings updated successfully', 'woonoow'),
], 200);
}
diff --git a/includes/Core/Bootstrap.php b/includes/Core/Bootstrap.php
index f8868b7..c2c8fcb 100644
--- a/includes/Core/Bootstrap.php
+++ b/includes/Core/Bootstrap.php
@@ -19,7 +19,6 @@ use WooNooW\Core\Mail\MailQueue;
use WooNooW\Core\Mail\WooEmailOverride;
use WooNooW\Core\DataStores\OrderStore;
use WooNooW\Core\MediaUpload;
-use WooNooW\Core\Notifications\NotificationManager;
use WooNooW\Branding;
class Bootstrap {
@@ -31,7 +30,6 @@ class Bootstrap {
StandaloneAdmin::init();
Branding::init();
MediaUpload::init();
- NotificationManager::init();
// Addon system (order matters: Registry → Routes → Navigation)
AddonRegistry::init();
diff --git a/includes/Core/Notifications/NotificationManager.php b/includes/Core/Notifications/NotificationManager.php
deleted file mode 100644
index fea52d9..0000000
--- a/includes/Core/Notifications/NotificationManager.php
+++ /dev/null
@@ -1,230 +0,0 @@
- 'email',
- 'label' => __('Email', 'woonoow'),
- 'icon' => 'mail',
- 'builtin' => true,
- 'enabled' => true,
- ]);
-
- // Register default notification events
- self::register_default_events();
-
- // Allow addons to register their channels
- add_action('woonoow_register_notification_channels', [__CLASS__, 'allow_addon_registration']);
- }
-
- /**
- * Register a notification channel
- *
- * @param string $id Channel ID
- * @param array $args Channel arguments
- */
- public static function register_channel($id, $args = []) {
- $defaults = [
- 'id' => $id,
- 'label' => ucfirst($id),
- 'icon' => 'bell',
- 'builtin' => false,
- 'enabled' => false,
- 'addon' => '',
- ];
-
- self::$channels[$id] = wp_parse_args($args, $defaults);
- }
-
- /**
- * Get all registered channels
- *
- * @return array
- */
- public static function get_channels() {
- return apply_filters('woonoow_notification_channels', self::$channels);
- }
-
- /**
- * Register default notification events
- */
- private static function register_default_events() {
- // Order events
- self::register_event('order_placed', [
- 'label' => __('Order Placed', 'woonoow'),
- 'description' => __('When a new order is placed', 'woonoow'),
- 'category' => 'orders',
- 'wc_email' => 'new_order', // Maps to WC_Email_New_Order
- ]);
-
- self::register_event('order_processing', [
- 'label' => __('Order Processing', 'woonoow'),
- 'description' => __('When order status changes to processing', 'woonoow'),
- 'category' => 'orders',
- 'wc_email' => 'customer_processing_order',
- ]);
-
- self::register_event('order_completed', [
- 'label' => __('Order Completed', 'woonoow'),
- 'description' => __('When order is marked as completed', 'woonoow'),
- 'category' => 'orders',
- 'wc_email' => 'customer_completed_order',
- ]);
-
- self::register_event('order_cancelled', [
- 'label' => __('Order Cancelled', 'woonoow'),
- 'description' => __('When order is cancelled', 'woonoow'),
- 'category' => 'orders',
- 'wc_email' => 'cancelled_order',
- ]);
-
- self::register_event('order_refunded', [
- 'label' => __('Order Refunded', 'woonoow'),
- 'description' => __('When order is refunded', 'woonoow'),
- 'category' => 'orders',
- 'wc_email' => 'customer_refunded_order',
- ]);
-
- // Product events
- self::register_event('low_stock', [
- 'label' => __('Low Stock Alert', 'woonoow'),
- 'description' => __('When product stock is low', 'woonoow'),
- 'category' => 'products',
- 'wc_email' => 'low_stock',
- ]);
-
- self::register_event('out_of_stock', [
- 'label' => __('Out of Stock Alert', 'woonoow'),
- 'description' => __('When product is out of stock', 'woonoow'),
- 'category' => 'products',
- 'wc_email' => 'no_stock',
- ]);
-
- // Customer events
- self::register_event('new_customer', [
- 'label' => __('New Customer', 'woonoow'),
- 'description' => __('When a new customer registers', 'woonoow'),
- 'category' => 'customers',
- 'wc_email' => 'customer_new_account',
- ]);
-
- self::register_event('customer_note', [
- 'label' => __('Customer Note Added', 'woonoow'),
- 'description' => __('When a note is added to customer order', 'woonoow'),
- 'category' => 'customers',
- 'wc_email' => 'customer_note',
- ]);
- }
-
- /**
- * Register a notification event
- *
- * @param string $id Event ID
- * @param array $args Event arguments
- */
- public static function register_event($id, $args = []) {
- $defaults = [
- 'id' => $id,
- 'label' => ucfirst(str_replace('_', ' ', $id)),
- 'description' => '',
- 'category' => 'general',
- 'wc_email' => '',
- 'channels' => [],
- ];
-
- self::$events[$id] = wp_parse_args($args, $defaults);
- }
-
- /**
- * Get all registered events
- *
- * @return array
- */
- public static function get_events() {
- return apply_filters('woonoow_notification_events', self::$events);
- }
-
- /**
- * Get events by category
- *
- * @param string $category Category name
- * @return array
- */
- public static function get_events_by_category($category) {
- $events = self::get_events();
- return array_filter($events, function($event) use ($category) {
- return $event['category'] === $category;
- });
- }
-
- /**
- * Send notification
- *
- * @param string $event_id Event ID
- * @param array $data Notification data
- * @param array $channels Channels to use (default: from settings)
- */
- public static function send($event_id, $data = [], $channels = null) {
- // Get event configuration
- $event = self::$events[$event_id] ?? null;
- if (!$event) {
- return;
- }
-
- // Get channels from settings if not specified
- if ($channels === null) {
- $settings = NotificationSettingsProvider::get_event_settings($event_id);
- $channels = $settings['channels'] ?? ['email'];
- }
-
- // Send via each enabled channel
- foreach ($channels as $channel_id) {
- // Email is handled by WooCommerce, skip it
- if ($channel_id === 'email') {
- continue;
- }
-
- // Fire action for addon channels
- do_action("woonoow_notification_send_{$channel_id}", $event_id, $data);
- }
- }
-
- /**
- * Allow addons to register channels
- */
- public static function allow_addon_registration() {
- // Addons hook into this to register their channels
- // Example: add_action('woonoow_register_notification_channels', function() {
- // NotificationManager::register_channel('whatsapp', [...]);
- // });
- }
-}
diff --git a/includes/Core/Notifications/NotificationSettingsProvider.php b/includes/Core/Notifications/NotificationSettingsProvider.php
deleted file mode 100644
index 297c07c..0000000
--- a/includes/Core/Notifications/NotificationSettingsProvider.php
+++ /dev/null
@@ -1,182 +0,0 @@
- self::get_default_event_settings(),
- 'channels' => self::get_default_channel_settings(),
- ];
- }
-
- /**
- * Get default event settings
- *
- * @return array
- */
- private static function get_default_event_settings() {
- $events = NotificationManager::get_events();
- $settings = [];
-
- foreach ($events as $event_id => $event) {
- $settings[$event_id] = [
- 'enabled' => true,
- 'channels' => ['email'], // Email enabled by default
- 'recipients' => [
- 'email' => 'admin', // admin, customer, or both
- ],
- ];
- }
-
- return $settings;
- }
-
- /**
- * Get default channel settings
- *
- * @return array
- */
- private static function get_default_channel_settings() {
- return [
- 'email' => [
- 'enabled' => true,
- // Email settings are managed by WooCommerce
- // We just track if it's enabled in our system
- ],
- ];
- }
-
- /**
- * Get settings for a specific event
- *
- * @param string $event_id Event ID
- * @return array
- */
- public static function get_event_settings($event_id) {
- $settings = self::get_settings();
- return $settings['events'][$event_id] ?? [];
- }
-
- /**
- * Get settings for a specific channel
- *
- * @param string $channel_id Channel ID
- * @return array
- */
- public static function get_channel_settings($channel_id) {
- $settings = self::get_settings();
- return $settings['channels'][$channel_id] ?? [];
- }
-
- /**
- * Update notification settings
- *
- * @param array $new_settings New settings
- * @return bool
- */
- public static function update_settings($new_settings) {
- $current = self::get_settings();
- $updated = wp_parse_args($new_settings, $current);
-
- return update_option(self::OPTION_KEY, $updated);
- }
-
- /**
- * Update event settings
- *
- * @param string $event_id Event ID
- * @param array $event_settings Event settings
- * @return bool
- */
- public static function update_event_settings($event_id, $event_settings) {
- $settings = self::get_settings();
- $settings['events'][$event_id] = $event_settings;
-
- return self::update_settings($settings);
- }
-
- /**
- * Update channel settings
- *
- * @param string $channel_id Channel ID
- * @param array $channel_settings Channel settings
- * @return bool
- */
- public static function update_channel_settings($channel_id, $channel_settings) {
- $settings = self::get_settings();
- $settings['channels'][$channel_id] = $channel_settings;
-
- return self::update_settings($settings);
- }
-
- /**
- * Check if event is enabled
- *
- * @param string $event_id Event ID
- * @return bool
- */
- public static function is_event_enabled($event_id) {
- $event_settings = self::get_event_settings($event_id);
- return $event_settings['enabled'] ?? true;
- }
-
- /**
- * Check if channel is enabled for event
- *
- * @param string $event_id Event ID
- * @param string $channel_id Channel ID
- * @return bool
- */
- public static function is_channel_enabled_for_event($event_id, $channel_id) {
- $event_settings = self::get_event_settings($event_id);
- $channels = $event_settings['channels'] ?? [];
-
- return in_array($channel_id, $channels, true);
- }
-
- /**
- * Get recipient type for event channel
- *
- * @param string $event_id Event ID
- * @param string $channel_id Channel ID
- * @return string admin|customer|both
- */
- public static function get_recipient_type($event_id, $channel_id) {
- $event_settings = self::get_event_settings($event_id);
- $recipients = $event_settings['recipients'] ?? [];
-
- return $recipients[$channel_id] ?? 'admin';
- }
-}