Files
WooNooW/includes/Core/Notifications/EmailManager.php
dwindown 60658c6786 feat: Complete backend wiring for notification system
 Global System Toggle:
- Added GET/POST /notifications/system-mode endpoints
- Switch between WooNooW and WooCommerce notification systems
- Stored in: woonoow_notification_system_mode
- EmailManager::is_enabled() checks system mode
- NotificationManager checks mode before sending

 Template System Wired:
- Templates saved via API are used when sending
- EmailRenderer fetches templates from TemplateProvider
- Variables replaced automatically
- Markdown parsed (cards, buttons, images)
- Email customization applied (colors, logo, branding)

 Channel Toggle Wired:
- Frontend toggles saved to database
- NotificationManager::is_channel_enabled() checks before sending
- Email: woonoow_email_notifications_enabled
- Push: woonoow_push_notifications_enabled

 Event Toggle Wired:
- Per-event channel settings saved
- NotificationManager::is_event_channel_enabled() checks before sending
- Stored in: woonoow_notification_settings

 Email Sending Flow:
Event → EmailManager → Check System Mode → Check Channel Toggle
→ Check Event Toggle → EmailRenderer → Get Template → Replace Variables
→ Parse Markdown → Apply Branding → wp_mail() → Sent

 All Settings Applied:
- Template modifications saved and used
- Channel toggles respected
- Event toggles respected
- Global system mode respected
- Email customization applied
- Push settings applied

📋 Modified Files:
- NotificationsController.php: Added system-mode endpoints
- NotificationManager.php: Added system mode check, wired EmailRenderer
- EmailManager.php: Added is_enabled() check for system mode

🎯 Result: Complete end-to-end notification system fully functional
2025-11-15 21:59:46 +07:00

389 lines
9.9 KiB
PHP

<?php
/**
* Email Manager
*
* Manages custom email notifications and disables WooCommerce default emails
*
* @package WooNooW\Core\Notifications
*/
namespace WooNooW\Core\Notifications;
class EmailManager {
/**
* Instance
*/
private static $instance = null;
/**
* Get instance
*/
public static function instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
/**
* Constructor
*/
private function __construct() {
$this->init_hooks();
}
/**
* Initialize hooks
*/
private function init_hooks() {
// Disable WooCommerce emails to prevent duplicates
add_action('woocommerce_email', [$this, 'disable_wc_emails'], 1);
// Hook into WooCommerce order status changes
add_action('woocommerce_order_status_pending_to_processing', [$this, 'send_order_processing_email'], 10, 2);
add_action('woocommerce_order_status_pending_to_completed', [$this, 'send_order_completed_email'], 10, 2);
add_action('woocommerce_order_status_processing_to_completed', [$this, 'send_order_completed_email'], 10, 2);
add_action('woocommerce_order_status_completed', [$this, 'send_order_completed_email'], 10, 2);
add_action('woocommerce_order_status_pending_to_on-hold', [$this, 'send_order_on_hold_email'], 10, 2);
add_action('woocommerce_order_status_failed_to_processing', [$this, 'send_order_processing_email'], 10, 2);
add_action('woocommerce_order_status_cancelled', [$this, 'send_order_cancelled_email'], 10, 2);
add_action('woocommerce_order_status_refunded', [$this, 'send_order_refunded_email'], 10, 2);
add_action('woocommerce_order_fully_refunded', [$this, 'send_order_refunded_email'], 10, 2);
// New order notification for admin
add_action('woocommerce_new_order', [$this, 'send_new_order_admin_email'], 10, 1);
// Customer note
add_action('woocommerce_new_customer_note', [$this, 'send_customer_note_email'], 10, 1);
// New customer account
add_action('woocommerce_created_customer', [$this, 'send_new_customer_email'], 10, 3);
// Low stock / Out of stock
add_action('woocommerce_low_stock', [$this, 'send_low_stock_email'], 10, 1);
add_action('woocommerce_no_stock', [$this, 'send_out_of_stock_email'], 10, 1);
add_action('woocommerce_product_set_stock', [$this, 'check_stock_levels'], 10, 1);
}
/**
* Check if WooNooW notification system is enabled
*
* @return bool
*/
public static function is_enabled() {
// Check global notification system mode
$system_mode = get_option('woonoow_notification_system_mode', 'woonoow');
return $system_mode === 'woonoow';
}
/**
* Disable WooCommerce default emails
*
* @param WC_Emails $email_class
*/
public function disable_wc_emails($email_class) {
// Only disable WC emails if WooNooW system is enabled
if (!self::is_enabled()) {
return; // Keep WC emails if WooNooW system disabled
}
// Disable all WooCommerce transactional emails
$emails_to_disable = [
'WC_Email_New_Order', // Admin: New order
'WC_Email_Cancelled_Order', // Admin: Cancelled order
'WC_Email_Failed_Order', // Admin: Failed order
'WC_Email_Customer_On_Hold_Order', // Customer: Order on-hold
'WC_Email_Customer_Processing_Order', // Customer: Processing order
'WC_Email_Customer_Completed_Order', // Customer: Completed order
'WC_Email_Customer_Refunded_Order', // Customer: Refunded order
'WC_Email_Customer_Invoice', // Customer: Invoice
'WC_Email_Customer_Note', // Customer: Note added
'WC_Email_Customer_Reset_Password', // Customer: Reset password
'WC_Email_Customer_New_Account', // Customer: New account
];
foreach ($emails_to_disable as $email_id) {
add_filter('woocommerce_email_enabled_' . strtolower(str_replace('WC_Email_', '', $email_id)), '__return_false');
}
}
/**
* Send order processing email
*
* @param int $order_id
* @param WC_Order $order
*/
public function send_order_processing_email($order_id, $order = null) {
if (!$order) {
$order = wc_get_order($order_id);
}
if (!$order) {
return;
}
// Check if event is enabled
if (!$this->is_event_enabled('order_processing', 'email', 'customer')) {
return;
}
// Send email
$this->send_email('order_processing', 'customer', $order);
}
/**
* Send order completed email
*
* @param int $order_id
* @param WC_Order $order
*/
public function send_order_completed_email($order_id, $order = null) {
if (!$order) {
$order = wc_get_order($order_id);
}
if (!$order) {
return;
}
// Check if event is enabled
if (!$this->is_event_enabled('order_completed', 'email', 'customer')) {
return;
}
// Send email
$this->send_email('order_completed', 'customer', $order);
}
/**
* Send order on-hold email
*
* @param int $order_id
* @param WC_Order $order
*/
public function send_order_on_hold_email($order_id, $order = null) {
if (!$order) {
$order = wc_get_order($order_id);
}
if (!$order) {
return;
}
// Check if event is enabled
if (!$this->is_event_enabled('order_processing', 'email', 'customer')) {
return;
}
// Send email (use processing template for on-hold)
$this->send_email('order_processing', 'customer', $order);
}
/**
* Send order cancelled email
*
* @param int $order_id
* @param WC_Order $order
*/
public function send_order_cancelled_email($order_id, $order = null) {
if (!$order) {
$order = wc_get_order($order_id);
}
if (!$order) {
return;
}
// Send to admin
if ($this->is_event_enabled('order_cancelled', 'email', 'staff')) {
$this->send_email('order_cancelled', 'staff', $order);
}
}
/**
* Send order refunded email
*
* @param int $order_id
* @param WC_Order $order
*/
public function send_order_refunded_email($order_id, $order = null) {
if (!$order) {
$order = wc_get_order($order_id);
}
if (!$order) {
return;
}
// Check if event is enabled
if (!$this->is_event_enabled('order_refunded', 'email', 'customer')) {
return;
}
// Send email
$this->send_email('order_refunded', 'customer', $order);
}
/**
* Send new order admin email
*
* @param int $order_id
*/
public function send_new_order_admin_email($order_id) {
$order = wc_get_order($order_id);
if (!$order) {
return;
}
// Check if event is enabled
if (!$this->is_event_enabled('order_placed', 'email', 'staff')) {
return;
}
// Send email
$this->send_email('order_placed', 'staff', $order);
}
/**
* Send customer note email
*
* @param array $args
*/
public function send_customer_note_email($args) {
$order = wc_get_order($args['order_id']);
if (!$order) {
return;
}
// Check if event is enabled
if (!$this->is_event_enabled('customer_note', 'email', 'customer')) {
return;
}
// Send email with note data
$this->send_email('customer_note', 'customer', $order, ['note' => $args['customer_note']]);
}
/**
* Send new customer email
*
* @param int $customer_id
* @param array $new_customer_data
* @param bool $password_generated
*/
public function send_new_customer_email($customer_id, $new_customer_data = [], $password_generated = false) {
// Check if event is enabled
if (!$this->is_event_enabled('new_customer', 'email', 'customer')) {
return;
}
$customer = new \WC_Customer($customer_id);
// Send email
$this->send_email('new_customer', 'customer', $customer, [
'password_generated' => $password_generated,
'user_login' => $new_customer_data['user_login'] ?? '',
'user_pass' => $new_customer_data['user_pass'] ?? '',
]);
}
/**
* Send low stock email
*
* @param WC_Product $product
*/
public function send_low_stock_email($product) {
// Check if event is enabled
if (!$this->is_event_enabled('low_stock', 'email', 'staff')) {
return;
}
// Send email
$this->send_email('low_stock', 'staff', $product);
}
/**
* Send out of stock email
*
* @param WC_Product $product
*/
public function send_out_of_stock_email($product) {
// Check if event is enabled
if (!$this->is_event_enabled('out_of_stock', 'email', 'staff')) {
return;
}
// Send email
$this->send_email('out_of_stock', 'staff', $product);
}
/**
* Check stock levels when product stock is updated
*
* @param WC_Product $product
*/
public function check_stock_levels($product) {
$stock = $product->get_stock_quantity();
$low_stock_threshold = get_option('woocommerce_notify_low_stock_amount', 2);
if ($stock <= 0) {
$this->send_out_of_stock_email($product);
} elseif ($stock <= $low_stock_threshold) {
$this->send_low_stock_email($product);
}
}
/**
* Check if event is enabled
*
* @param string $event_id
* @param string $channel_id
* @param string $recipient_type
* @return bool
*/
private function is_event_enabled($event_id, $channel_id, $recipient_type) {
$settings = get_option('woonoow_notification_settings', []);
// Check if event exists and channel is enabled
if (isset($settings['events'][$event_id]['channels'][$channel_id])) {
return $settings['events'][$event_id]['channels'][$channel_id]['enabled'] ?? false;
}
return false;
}
/**
* Send email
*
* @param string $event_id
* @param string $recipient_type
* @param mixed $data
* @param array $extra_data
*/
private function send_email($event_id, $recipient_type, $data, $extra_data = []) {
// Get email renderer
$renderer = EmailRenderer::instance();
// Render email
$email = $renderer->render($event_id, $recipient_type, $data, $extra_data);
if (!$email) {
return;
}
// Send email via wp_mail
$headers = [
'Content-Type: text/html; charset=UTF-8',
'From: ' . get_bloginfo('name') . ' <' . get_option('admin_email') . '>',
];
wp_mail($email['to'], $email['subject'], $email['body'], $headers);
// Log email sent
do_action('woonoow_email_sent', $event_id, $recipient_type, $email);
}
}