namespace, '/' . $this->rest_base . '/channels', [ [ 'methods' => 'GET', 'callback' => [$this, 'get_channels'], 'permission_callback' => [$this, 'check_permission'], ], ]); // GET /woonoow/v1/notifications/events register_rest_route($this->namespace, '/' . $this->rest_base . '/events', [ [ 'methods' => 'GET', 'callback' => [$this, 'get_events'], 'permission_callback' => [$this, 'check_permission'], ], ]); // POST /woonoow/v1/notifications/events/update register_rest_route($this->namespace, '/' . $this->rest_base . '/events/update', [ [ 'methods' => 'POST', 'callback' => [$this, 'update_event'], 'permission_callback' => [$this, 'check_permission'], ], ]); // GET /woonoow/v1/notifications/templates register_rest_route($this->namespace, '/' . $this->rest_base . '/templates', [ [ 'methods' => 'GET', 'callback' => [$this, 'get_templates'], 'permission_callback' => [$this, 'check_permission'], ], ]); // GET /woonoow/v1/notifications/templates/:eventId/:channelId register_rest_route($this->namespace, '/' . $this->rest_base . '/templates/(?P[a-zA-Z0-9_-]+)/(?P[a-zA-Z0-9_-]+)', [ [ 'methods' => 'GET', 'callback' => [$this, 'get_template'], 'permission_callback' => [$this, 'check_permission'], ], ]); // POST /woonoow/v1/notifications/templates register_rest_route($this->namespace, '/' . $this->rest_base . '/templates', [ [ 'methods' => 'POST', 'callback' => [$this, 'save_template'], 'permission_callback' => [$this, 'check_permission'], ], ]); // DELETE /woonoow/v1/notifications/templates/:eventId/:channelId register_rest_route($this->namespace, '/' . $this->rest_base . '/templates/(?P[a-zA-Z0-9_-]+)/(?P[a-zA-Z0-9_-]+)', [ [ 'methods' => 'DELETE', 'callback' => [$this, 'delete_template'], 'permission_callback' => [$this, 'check_permission'], ], ]); // GET /woonoow/v1/notifications/push/vapid-key register_rest_route($this->namespace, '/' . $this->rest_base . '/push/vapid-key', [ [ 'methods' => 'GET', 'callback' => [$this, 'get_vapid_key'], 'permission_callback' => '__return_true', ], ]); // POST /woonoow/v1/notifications/push/subscribe register_rest_route($this->namespace, '/' . $this->rest_base . '/push/subscribe', [ [ 'methods' => 'POST', 'callback' => [$this, 'push_subscribe'], 'permission_callback' => '__return_true', ], ]); // POST /woonoow/v1/notifications/push/unsubscribe register_rest_route($this->namespace, '/' . $this->rest_base . '/push/unsubscribe', [ [ 'methods' => 'POST', 'callback' => [$this, 'push_unsubscribe'], 'permission_callback' => '__return_true', ], ]); // GET /woonoow/v1/notifications/push/settings register_rest_route($this->namespace, '/' . $this->rest_base . '/push/settings', [ [ 'methods' => 'GET', 'callback' => [$this, 'get_push_settings'], 'permission_callback' => [$this, 'check_permission'], ], ]); // POST /woonoow/v1/notifications/push/settings register_rest_route($this->namespace, '/' . $this->rest_base . '/push/settings', [ [ 'methods' => 'POST', 'callback' => [$this, 'update_push_settings'], 'permission_callback' => [$this, 'check_permission'], ], ]); // POST /woonoow/v1/notifications/channels/toggle register_rest_route($this->namespace, '/' . $this->rest_base . '/channels/toggle', [ [ 'methods' => 'POST', 'callback' => [$this, 'toggle_channel'], 'permission_callback' => [$this, 'check_permission'], ], ]); // GET /woonoow/v1/notifications/staff/events register_rest_route($this->namespace, '/' . $this->rest_base . '/staff/events', [ [ 'methods' => 'GET', 'callback' => [$this, 'get_staff_events'], 'permission_callback' => [$this, 'check_permission'], ], ]); // GET /woonoow/v1/notifications/customer/events register_rest_route($this->namespace, '/' . $this->rest_base . '/customer/events', [ [ 'methods' => 'GET', 'callback' => [$this, 'get_customer_events'], 'permission_callback' => [$this, 'check_permission'], ], ]); } /** * Get available notification channels * * @param WP_REST_Request $request Request object * @return WP_REST_Response */ public function get_channels(WP_REST_Request $request) { // Get channel enabled states $email_enabled = get_option('woonoow_email_notifications_enabled', true); $push_enabled = get_option('woonoow_push_notifications_enabled', true); $channels = [ [ 'id' => 'email', 'label' => __('Email', 'woonoow'), 'icon' => 'mail', 'enabled' => (bool) $email_enabled, 'builtin' => true, ], [ 'id' => 'push', 'label' => __('Push Notifications', 'woonoow'), 'icon' => 'bell', 'enabled' => (bool) $push_enabled, 'builtin' => true, ], ]; // Allow addons to register their channels $channels = apply_filters('woonoow_notification_channels', $channels); return new WP_REST_Response($channels, 200); } /** * Get notification events * * @param WP_REST_Request $request Request object * @return WP_REST_Response */ public function get_events(WP_REST_Request $request) { // Get saved settings $settings = get_option('woonoow_notification_settings', []); // 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']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'admin'], 'push' => ['enabled' => false, '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']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'customer'], 'push' => ['enabled' => false, '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']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'customer'], 'push' => ['enabled' => false, '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']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'admin'], 'push' => ['enabled' => false, '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']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'customer'], 'push' => ['enabled' => false, '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']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'admin'], 'push' => ['enabled' => false, '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']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'admin'], 'push' => ['enabled' => false, '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']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'customer'], 'push' => ['enabled' => false, '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']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'customer'], 'push' => ['enabled' => false, 'recipient' => 'customer']], ], ], ]; // Allow addons to add custom events $events = apply_filters('woonoow_notification_events', $events); return new WP_REST_Response($events, 200); } /** * Get staff notification events (admin/staff recipient) * * @param WP_REST_Request $request Request object * @return WP_REST_Response */ public function get_staff_events(WP_REST_Request $request) { $all_events = $this->get_all_events(); // Filter events where recipient_type is 'staff' $staff_events = []; foreach ($all_events as $category => $events) { $filtered = array_filter($events, function($event) { return ($event['recipient_type'] ?? 'staff') === 'staff'; }); if (!empty($filtered)) { $staff_events[$category] = array_values($filtered); } } return new WP_REST_Response($staff_events, 200); } /** * Get customer notification events (customer recipient) * * @param WP_REST_Request $request Request object * @return WP_REST_Response */ public function get_customer_events(WP_REST_Request $request) { $all_events = $this->get_all_events(); // Filter events where recipient_type is 'customer' $customer_events = []; foreach ($all_events as $category => $events) { $filtered = array_filter($events, function($event) { return ($event['recipient_type'] ?? 'staff') === 'customer'; }); if (!empty($filtered)) { $customer_events[$category] = array_values($filtered); } } return new WP_REST_Response($customer_events, 200); } /** * Get all events (internal helper) * * @return array */ private function get_all_events() { // Get saved settings $settings = get_option('woonoow_notification_settings', []); // Define all events $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, 'recipient_type' => 'staff', 'channels' => $settings['order_placed']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'admin'], 'push' => ['enabled' => false, '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, 'recipient_type' => 'customer', 'channels' => $settings['order_processing']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'customer'], 'push' => ['enabled' => false, '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, 'recipient_type' => 'customer', 'channels' => $settings['order_completed']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'customer'], 'push' => ['enabled' => false, 'recipient' => 'customer']], ], [ 'id' => 'order_cancelled', 'label' => __('Order Cancelled', 'woonoow'), 'description' => __('When order is cancelled', 'woonoow'), 'category' => 'orders', 'wc_email' => 'cancelled_order', 'enabled' => true, 'recipient_type' => 'staff', 'channels' => $settings['order_cancelled']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'admin'], 'push' => ['enabled' => false, 'recipient' => 'admin']], ], [ 'id' => 'order_refunded', 'label' => __('Order Refunded', 'woonoow'), 'description' => __('When order is refunded', 'woonoow'), 'category' => 'orders', 'wc_email' => 'customer_refunded_order', 'enabled' => true, 'recipient_type' => 'customer', 'channels' => $settings['order_refunded']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'customer'], 'push' => ['enabled' => false, '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, 'recipient_type' => 'staff', 'channels' => $settings['low_stock']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'admin'], 'push' => ['enabled' => false, '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, 'recipient_type' => 'staff', 'channels' => $settings['out_of_stock']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'admin'], 'push' => ['enabled' => false, '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, 'recipient_type' => 'customer', 'channels' => $settings['new_customer']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'customer'], 'push' => ['enabled' => false, '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, 'recipient_type' => 'customer', 'channels' => $settings['customer_note']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'customer'], 'push' => ['enabled' => false, 'recipient' => 'customer']], ], ], ]; // Allow addons to add custom events return apply_filters('woonoow_notification_events', $events); } /** * Update event settings * * @param WP_REST_Request $request Request object * @return WP_REST_Response|WP_Error */ public function update_event(WP_REST_Request $request) { $params = $request->get_json_params(); $event_id = isset($params['eventId']) ? $params['eventId'] : null; $channel_id = isset($params['channelId']) ? $params['channelId'] : null; $enabled = isset($params['enabled']) ? $params['enabled'] : null; $recipient = isset($params['recipient']) ? $params['recipient'] : null; if (empty($event_id) || empty($channel_id)) { return new WP_Error( 'invalid_params', __('Event ID and Channel ID are required', 'woonoow'), ['status' => 400] ); } // Get current settings $settings = get_option('woonoow_notification_settings', []); // Update settings if (!isset($settings[$event_id])) { $settings[$event_id] = ['channels' => []]; } if (!isset($settings[$event_id]['channels'])) { $settings[$event_id]['channels'] = []; } $settings[$event_id]['channels'][$channel_id] = [ 'enabled' => (bool) $enabled, 'recipient' => $recipient ?? 'admin', ]; // Save settings update_option('woonoow_notification_settings', $settings, false); // 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' => __('Event settings updated successfully', 'woonoow'), ], 200); } /** * Check if user has permission * * @return bool */ public function check_permission() { return current_user_can('manage_woocommerce') || current_user_can('manage_options'); } /** * Get all templates * * @param WP_REST_Request $request Request object * @return WP_REST_Response */ public function get_templates(WP_REST_Request $request) { $templates = TemplateProvider::get_templates(); return new WP_REST_Response($templates, 200); } /** * Get single template * * @param WP_REST_Request $request Request object * @return WP_REST_Response|WP_Error */ public function get_template(WP_REST_Request $request) { $event_id = $request->get_param('eventId'); $channel_id = $request->get_param('channelId'); $template = TemplateProvider::get_template($event_id, $channel_id); if (!$template) { return new WP_Error( 'template_not_found', __('Template not found', 'woonoow'), ['status' => 404] ); } return new WP_REST_Response($template, 200); } /** * Save template * * @param WP_REST_Request $request Request object * @return WP_REST_Response|WP_Error */ public function save_template(WP_REST_Request $request) { $event_id = $request->get_param('eventId'); $channel_id = $request->get_param('channelId'); $subject = $request->get_param('subject'); $body = $request->get_param('body'); if (empty($event_id) || empty($channel_id)) { return new WP_Error( 'invalid_params', __('Event ID and Channel ID are required', 'woonoow'), ['status' => 400] ); } $success = TemplateProvider::save_template($event_id, $channel_id, [ 'subject' => $subject, 'body' => $body, ]); if (!$success) { return new WP_Error( 'save_failed', __('Failed to save template', 'woonoow'), ['status' => 500] ); } return new WP_REST_Response([ 'success' => true, 'message' => __('Template saved successfully', 'woonoow'), ], 200); } /** * Delete template (revert to default) * * @param WP_REST_Request $request Request object * @return WP_REST_Response */ public function delete_template(WP_REST_Request $request) { $event_id = $request->get_param('eventId'); $channel_id = $request->get_param('channelId'); TemplateProvider::delete_template($event_id, $channel_id); return new WP_REST_Response([ 'success' => true, 'message' => __('Template reverted to default', 'woonoow'), ], 200); } /** * Get VAPID public key for push notifications * * @param WP_REST_Request $request Request object * @return WP_REST_Response */ public function get_vapid_key(WP_REST_Request $request) { $public_key = PushNotificationHandler::get_public_key(); return new WP_REST_Response([ 'publicKey' => $public_key, ], 200); } /** * Subscribe to push notifications * * @param WP_REST_Request $request Request object * @return WP_REST_Response|WP_Error */ public function push_subscribe(WP_REST_Request $request) { $subscription = $request->get_param('subscription'); $user_id = get_current_user_id(); if (empty($subscription)) { return new WP_Error( 'invalid_subscription', __('Subscription data is required', 'woonoow'), ['status' => 400] ); } $success = PushNotificationHandler::subscribe($subscription, $user_id); if (!$success) { return new WP_Error( 'subscribe_failed', __('Failed to subscribe to push notifications', 'woonoow'), ['status' => 500] ); } return new WP_REST_Response([ 'success' => true, 'message' => __('Subscribed to push notifications', 'woonoow'), ], 200); } /** * Unsubscribe from push notifications * * @param WP_REST_Request $request Request object * @return WP_REST_Response */ public function push_unsubscribe(WP_REST_Request $request) { $subscription_id = $request->get_param('subscriptionId'); PushNotificationHandler::unsubscribe($subscription_id); return new WP_REST_Response([ 'success' => true, 'message' => __('Unsubscribed from push notifications', 'woonoow'), ], 200); } /** * Get push notification settings * * @param WP_REST_Request $request Request object * @return WP_REST_Response */ public function get_push_settings(WP_REST_Request $request) { $settings = PushNotificationHandler::get_settings(); return new WP_REST_Response($settings, 200); } /** * Update push notification settings * * @param WP_REST_Request $request Request object * @return WP_REST_Response */ public function update_push_settings(WP_REST_Request $request) { $settings = $request->get_json_params(); if (empty($settings)) { return new WP_Error( 'invalid_settings', __('Settings data is required', 'woonoow'), ['status' => 400] ); } $success = PushNotificationHandler::update_settings($settings); if (!$success) { return new WP_Error( 'update_failed', __('Failed to update push notification settings', 'woonoow'), ['status' => 500] ); } return new WP_REST_Response([ 'success' => true, 'message' => __('Push notification settings updated', 'woonoow'), 'settings' => PushNotificationHandler::get_settings(), ], 200); } /** * Toggle notification channel * * @param WP_REST_Request $request Request object * @return WP_REST_Response */ public function toggle_channel(WP_REST_Request $request) { $params = $request->get_json_params(); $channel_id = isset($params['channelId']) ? $params['channelId'] : null; $enabled = isset($params['enabled']) ? $params['enabled'] : null; if (empty($channel_id)) { return new WP_Error( 'invalid_channel', __('Channel ID is required', 'woonoow'), ['status' => 400] ); } if ($enabled === null) { return new WP_Error( 'invalid_enabled', __('Enabled parameter is required', 'woonoow'), ['status' => 400] ); } // Only allow toggling built-in channels $option_key = ''; if ($channel_id === 'email') { $option_key = 'woonoow_email_notifications_enabled'; } elseif ($channel_id === 'push') { $option_key = 'woonoow_push_notifications_enabled'; } else { return new WP_Error( 'invalid_channel', __('Invalid channel ID', 'woonoow'), ['status' => 400] ); } // Update the option update_option($option_key, (bool) $enabled, false); // false = don't autoload // Verify the update $verified = get_option($option_key); return new WP_REST_Response([ 'success' => true, 'message' => sprintf( __('%s notifications %s', 'woonoow'), $channel_id === 'email' ? __('Email', 'woonoow') : __('Push', 'woonoow'), $enabled ? __('enabled', 'woonoow') : __('disabled', 'woonoow') ), 'channelId' => $channel_id, 'enabled' => (bool) $verified, ], 200); } }