diff --git a/EMAIL_DEBUGGING_GUIDE.md b/EMAIL_DEBUGGING_GUIDE.md new file mode 100644 index 0000000..2676d5b --- /dev/null +++ b/EMAIL_DEBUGGING_GUIDE.md @@ -0,0 +1,343 @@ +# Email Debugging Guide + +## ๐ Problem: Emails Not Sending + +Action Scheduler shows "Complete" but no emails appear in Email Log plugin. + +## ๐ Diagnostic Tools + +### 1. Check Settings +``` +Visit: /wp-content/plugins/woonoow/check-settings.php +``` +This shows: +- Notification system mode +- Email channel status +- Event configuration +- Template configuration +- Hook registration status +- Action Scheduler stats +- Queued emails + +### 2. Test Email Flow +``` +Visit: /wp-content/plugins/woonoow/test-email-flow.php +``` +Interactive dashboard with: +- System status +- Test buttons +- Queue viewer +- Action Scheduler monitor + +### 3. Direct Email Test +``` +Visit: /wp-content/plugins/woonoow/test-email-direct.php +``` +Or via WP-CLI: +```bash +wp eval-file wp-content/plugins/woonoow/test-email-direct.php +``` + +This: +- Queues a test email +- Manually triggers sendNow() +- Tests wp_mail() directly +- Shows detailed output + +## ๐ฌ Debug Logs to Check + +Enable debug logging in `wp-config.php`: +```php +define('WP_DEBUG', true); +define('WP_DEBUG_LOG', true); +define('WP_DEBUG_DISPLAY', false); +``` + +Then check `/wp-content/debug.log` for: + +### Expected Log Flow: + +``` +[EmailManager] send_order_processing_email triggered for order #123 +[EmailManager] Sending order_processing email for order #123 +[EmailManager] send_email called - Event: order_processing, Recipient: customer +[EmailManager] Email rendered successfully - To: customer@example.com, Subject: Order Processing +[EmailManager] wp_mail called - Result: success +[WooNooW MailQueue] Queued email ID: woonoow_mail_xxx_123456 +[WooNooW MailQueue] Hook registered: woonoow/mail/send -> MailQueue::sendNow +[WooNooW MailQueue] sendNow() called with args: Array(...) +[WooNooW MailQueue] email_id type: string +[WooNooW MailQueue] email_id value: 'woonoow_mail_xxx_123456' +[WooNooW MailQueue] Processing email_id: woonoow_mail_xxx_123456 +[WooNooW MailQueue] Payload retrieved - To: customer@example.com, Subject: Order Processing +[WooNooW MailQueue] Disabling WooEmailOverride to prevent loop +[WooNooW MailQueue] Calling wp_mail() now... +[WooNooW MailQueue] wp_mail() returned: TRUE (success) +[WooNooW MailQueue] Re-enabling WooEmailOverride +[WooNooW MailQueue] Sent and deleted email ID: woonoow_mail_xxx_123456 +``` + +## ๐ Common Issues & Solutions + +### Issue 1: No logs at all +**Symptom:** No `[EmailManager]` logs when order status changes + +**Cause:** Hooks not firing or EmailManager not initialized + +**Solution:** +1. Check `includes/Core/Bootstrap.php` - ensure `EmailManager::instance()` is called +2. Check WooCommerce is active +3. Check order status is actually changing + +**Test:** +```php +// Add to functions.php temporarily +add_action('woocommerce_order_status_changed', function($order_id, $old_status, $new_status) { + error_log("Order #$order_id status changed: $old_status -> $new_status"); +}, 10, 3); +``` + +### Issue 2: "order_processing email is disabled in settings" +**Symptom:** Log shows event is disabled + +**Cause:** Event not enabled in notification settings + +**Solution:** +1. Visit: WooNooW > Notifications +2. Find "Order Processing" event +3. Enable "Email" channel +4. Save settings + +**Verify:** +```bash +wp option get woonoow_notification_settings --format=json +``` + +### Issue 3: "Email rendering failed" +**Symptom:** `[EmailManager] Email rendering failed for event: order_processing` + +**Cause:** Template not configured or invalid + +**Solution:** +1. Visit: WooNooW > Email Templates +2. Configure template for "order_processing" +3. Add subject and content +4. Save template + +### Issue 4: sendNow() never called +**Symptom:** Action Scheduler shows "Complete" but no `[WooNooW MailQueue] sendNow()` logs + +**Cause:** Hook not registered or Action Scheduler passing wrong arguments + +**Solution:** +1. Check `[WooNooW MailQueue] Hook registered` appears in logs +2. If not, check `includes/Core/Bootstrap.php` - ensure `MailQueue::init()` is called +3. Check Action Scheduler arguments in database: +```sql +SELECT action_id, hook, args, status +FROM wp_actionscheduler_actions +WHERE hook = 'woonoow/mail/send' +ORDER BY action_id DESC +LIMIT 10; +``` + +### Issue 5: sendNow() called but no email_id +**Symptom:** `[WooNooW MailQueue] ERROR: No email_id provided` + +**Cause:** Action Scheduler passing empty or wrong arguments + +**Check logs for:** +``` +[WooNooW MailQueue] email_id type: NULL +[WooNooW MailQueue] email_id value: NULL +``` + +**Solution:** +The code now handles both string and array arguments. If still failing, check Action Scheduler args format. + +### Issue 6: Payload not found in wp_options +**Symptom:** `[WooNooW MailQueue] ERROR: Email payload not found for ID: xxx` + +**Cause:** Option was deleted before sendNow() ran, or never created + +**Solution:** +1. Check if email was queued: `[WooNooW MailQueue] Queued email ID: xxx` +2. Check database: +```sql +SELECT option_name, option_value +FROM wp_options +WHERE option_name LIKE 'woonoow_mail_%'; +``` +3. If missing, check `MailQueue::enqueue()` is being called + +### Issue 7: wp_mail() returns FALSE +**Symptom:** `[WooNooW MailQueue] wp_mail() returned: FALSE (failed)` + +**Cause:** SMTP configuration issue, not a plugin issue + +**Solution:** +1. Test wp_mail() directly: +```php +wp_mail('test@example.com', 'Test', 'Test message'); +``` +2. Check SMTP plugin configuration +3. Check server mail logs +4. Use Email Log plugin to see error messages + +### Issue 8: Notification system mode is "woocommerce" +**Symptom:** No WooNooW emails sent, WooCommerce default emails sent instead + +**Cause:** Global toggle set to use WooCommerce emails + +**Solution:** +1. Visit: WooNooW > Settings +2. Find "Notification System Mode" +3. Set to "WooNooW" +4. Save + +**Verify:** +```bash +wp option get woonoow_notification_system_mode +# Should return: woonoow +``` + +## ๐งช Testing Procedure + +### Step 1: Check Configuration +``` +Visit: /wp-content/plugins/woonoow/check-settings.php +``` +Ensure: +- โ System mode = "woonoow" +- โ Email channel = enabled +- โ Events have email enabled +- โ Hooks are registered + +### Step 2: Test Direct Email +``` +Visit: /wp-content/plugins/woonoow/test-email-direct.php +``` +This will: +1. Queue a test email +2. Manually trigger sendNow() +3. Test wp_mail() directly + +Check: +- โ Email appears in Email Log plugin +- โ Email received in inbox +- โ Debug logs show full flow + +### Step 3: Test Order Email +1. Create a test order +2. Change status to "Processing" +3. Check debug logs for full flow +4. Check Email Log plugin +5. Check inbox + +### Step 4: Monitor Action Scheduler +``` +Visit: /wp-admin/admin.php?page=wc-status&tab=action-scheduler +``` +Filter by hook: `woonoow/mail/send` + +Check: +- โ Actions are created +- โ Actions complete successfully +- โ No failed actions +- โ Args contain email_id + +## ๐ง Manual Fixes + +### Reset Notification Settings +```bash +wp option delete woonoow_notification_settings +wp option delete woonoow_email_templates +wp option delete woonoow_notification_system_mode +``` +Then reconfigure in admin. + +### Clear Email Queue +```bash +wp option list --search='woonoow_mail_*' --format=ids | xargs -I % wp option delete % +``` + +### Clear Action Scheduler Queue +```bash +wp action-scheduler clean --hooks=woonoow/mail/send +``` + +### Force Process Queue +```php +// Add to functions.php temporarily +add_action('init', function() { + if (function_exists('as_run_queue')) { + as_run_queue(); + } +}); +``` + +## ๐ Monitoring + +### Check Email Queue Size +```sql +SELECT COUNT(*) as queued_emails +FROM wp_options +WHERE option_name LIKE 'woonoow_mail_%'; +``` + +### Check Action Scheduler Stats +```sql +SELECT status, COUNT(*) as count +FROM wp_actionscheduler_actions +WHERE hook = 'woonoow/mail/send' +GROUP BY status; +``` + +### Recent Email Activity +```bash +tail -f /path/to/wp-content/debug.log | grep -E '\[EmailManager\]|\[WooNooW MailQueue\]' +``` + +## ๐ฏ Quick Checklist + +Before reporting an issue, verify: + +- [ ] WP_DEBUG enabled and logs checked +- [ ] Notification system mode = "woonoow" +- [ ] Email channel globally enabled +- [ ] Specific event has email enabled +- [ ] Email template configured for event +- [ ] MailQueue hook registered (check logs) +- [ ] Action Scheduler available and working +- [ ] SMTP configured and wp_mail() works +- [ ] Email Log plugin installed to monitor +- [ ] Ran check-settings.php +- [ ] Ran test-email-direct.php +- [ ] Checked debug logs for full flow + +## ๐ Reporting Issues + +When reporting email issues, provide: + +1. Output of `check-settings.php` +2. Output of `test-email-direct.php` +3. Debug log excerpt (last 100 lines with email-related entries) +4. Action Scheduler screenshot (filtered by woonoow/mail/send) +5. Email Log plugin screenshot +6. Steps to reproduce + +## ๐ Next Steps + +If all diagnostics pass but emails still not sending: + +1. Check server mail logs +2. Check SMTP relay logs +3. Check spam folder +4. Test with different email address +5. Disable other email plugins temporarily +6. Check WordPress mail configuration + +--- + +**Last Updated:** 2025-11-18 +**Version:** 1.0 diff --git a/check-settings.php b/check-settings.php new file mode 100644 index 0000000..924b267 --- /dev/null +++ b/check-settings.php @@ -0,0 +1,178 @@ + $event_data) { + echo " - $event_id:\n"; + + if (isset($event_data['channels']['email'])) { + $email_config = $event_data['channels']['email']; + $enabled = $email_config['enabled'] ?? false; + $status = $enabled ? 'โ ENABLED' : 'โ DISABLED'; + echo " Email: $status\n"; + + if (isset($email_config['recipients'])) { + echo " Recipients: " . implode(', ', array_keys($email_config['recipients'])) . "\n"; + } + } else { + echo " Email: โ NOT CONFIGURED\n"; + } + } + } else { + echo " โ No events configured\n"; + } +} + +// 4. Email Templates +echo "\n4. Email Templates:\n"; +$templates = get_option('woonoow_email_templates', []); + +if (empty($templates)) { + echo " โ No email templates found!\n"; +} else { + echo " โ " . count($templates) . " template(s) found\n"; + foreach ($templates as $template_id => $template_data) { + echo " - $template_id: " . ($template_data['subject'] ?? 'no subject') . "\n"; + } +} + +// 5. WooCommerce Hooks +echo "\n5. WooCommerce Hook Status:\n"; +global $wp_filter; + +$hooks_to_check = [ + 'woocommerce_order_status_pending_to_processing', + 'woocommerce_order_status_pending_to_completed', + 'woocommerce_order_status_processing_to_completed', + 'woocommerce_order_status_completed', +]; + +foreach ($hooks_to_check as $hook) { + if (isset($wp_filter[$hook])) { + $callbacks = $wp_filter[$hook]->callbacks; + $count = 0; + foreach ($callbacks as $priority => $funcs) { + $count += count($funcs); + } + echo " โ $hook: $count callback(s)\n"; + } else { + echo " โ $hook: NOT REGISTERED\n"; + } +} + +// 6. Mail Queue Hook +echo "\n6. Mail Queue Hook:\n"; +if (isset($wp_filter['woonoow/mail/send'])) { + echo " โ woonoow/mail/send: REGISTERED\n"; +} else { + echo " โ woonoow/mail/send: NOT REGISTERED\n"; + echo " This means MailQueue::init() was not called!\n"; +} + +// 7. Action Scheduler +echo "\n7. Action Scheduler:\n"; +if (function_exists('as_enqueue_async_action')) { + echo " โ Available\n"; + + global $wpdb; + $stats = [ + 'pending' => $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}actionscheduler_actions WHERE hook = 'woonoow/mail/send' AND status = 'pending'"), + 'complete' => $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}actionscheduler_actions WHERE hook = 'woonoow/mail/send' AND status = 'complete'"), + 'failed' => $wpdb->get_var("SELECT COUNT(*) FROM {$wpdb->prefix}actionscheduler_actions WHERE hook = 'woonoow/mail/send' AND status = 'failed'"), + ]; + + echo " Pending: {$stats['pending']}\n"; + echo " Complete: {$stats['complete']}\n"; + echo " Failed: {$stats['failed']}\n"; +} else { + echo " โ Not available (using wp-cron)\n"; +} + +// 8. Queued Emails +echo "\n8. Queued Emails (wp_options):\n"; +global $wpdb; +$queued = $wpdb->get_results( + "SELECT option_name, LENGTH(option_value) as size FROM {$wpdb->options} + WHERE option_name LIKE 'woonoow_mail_%' + ORDER BY option_id DESC LIMIT 10" +); + +if (empty($queued)) { + echo " โ No emails in queue\n"; +} else { + echo " " . count($queued) . " email(s) in queue:\n"; + foreach ($queued as $row) { + echo " - {$row->option_name} ({$row->size} bytes)\n"; + } +} + +echo "\n=== Summary ===\n"; +echo "System Mode: $system_mode\n"; +echo "Email Channel: " . ($email_enabled ? 'enabled' : 'disabled') . "\n"; +echo "Events Configured: " . (isset($settings['events']) ? count($settings['events']) : 0) . "\n"; +echo "Templates: " . count($templates) . "\n"; +echo "Queued Emails: " . count($queued) . "\n"; + +echo "\n=== Recommendations ===\n"; +if ($system_mode !== 'woonoow') { + echo "โ Set notification system mode to 'woonoow'\n"; +} +if (!$email_enabled) { + echo "โ Enable email channel\n"; +} +if (empty($settings['events'])) { + echo "โ Configure events in notification settings\n"; +} +if (!isset($wp_filter['woonoow/mail/send'])) { + echo "โ MailQueue hook not registered - check Bootstrap::init()\n"; +} + +echo "\nDone!\n"; diff --git a/test-email-direct.php b/test-email-direct.php new file mode 100644 index 0000000..a9ef1ef --- /dev/null +++ b/test-email-direct.php @@ -0,0 +1,134 @@ +callbacks[10]) . "\n"; +} else { + echo " โ Hook 'woonoow/mail/send' is NOT registered!\n"; + echo " This means MailQueue::init() was not called.\n"; +} + +// Test 2: Queue a test email +echo "\n2. Queuing test email...\n"; +$test_payload = [ + 'to' => get_option('admin_email'), + 'subject' => 'Direct Test - ' . date('H:i:s'), + 'html' => '
This is a direct test email.
', + 'headers' => ['Content-Type: text/html; charset=UTF-8'], + 'attachments' => [], +]; + +\WooNooW\Core\Mail\MailQueue::enqueue($test_payload); +echo " โ Email queued\n"; + +// Test 3: Check wp_options for queued email +echo "\n3. Checking wp_options for queued emails...\n"; +global $wpdb; +$queued = $wpdb->get_results( + "SELECT option_name FROM {$wpdb->options} WHERE option_name LIKE 'woonoow_mail_%' ORDER BY option_id DESC LIMIT 5" +); + +if (empty($queued)) { + echo " โ No emails found in wp_options!\n"; +} else { + echo " โ Found " . count($queued) . " queued email(s):\n"; + foreach ($queued as $row) { + echo " - " . $row->option_name . "\n"; + } +} + +// Test 4: Check Action Scheduler +echo "\n4. Checking Action Scheduler...\n"; +if (function_exists('as_enqueue_async_action')) { + $pending = $wpdb->get_var( + "SELECT COUNT(*) FROM {$wpdb->prefix}actionscheduler_actions + WHERE hook = 'woonoow/mail/send' AND status = 'pending'" + ); + echo " โ Action Scheduler available\n"; + echo " Pending actions: $pending\n"; + + // Get the most recent action + $recent = $wpdb->get_row( + "SELECT * FROM {$wpdb->prefix}actionscheduler_actions + WHERE hook = 'woonoow/mail/send' + ORDER BY action_id DESC LIMIT 1" + ); + + if ($recent) { + echo " Most recent action:\n"; + echo " ID: " . $recent->action_id . "\n"; + echo " Status: " . $recent->status . "\n"; + echo " Args: " . $recent->args . "\n"; + echo " Scheduled: " . $recent->scheduled_date_gmt . "\n"; + } +} else { + echo " โ Action Scheduler not available\n"; +} + +// Test 5: Manually trigger sendNow() with the queued email +echo "\n5. Manually triggering sendNow()...\n"; +if (!empty($queued)) { + $email_id = $queued[0]->option_name; + echo " Using email_id: $email_id\n"; + echo " Calling MailQueue::sendNow()...\n"; + + \WooNooW\Core\Mail\MailQueue::sendNow($email_id); + + echo " โ sendNow() called\n"; + echo " Check debug.log for detailed output\n"; +} else { + echo " โ No email to send\n"; +} + +// Test 6: Check if email was sent +echo "\n6. Checking if email was sent...\n"; +$still_queued = $wpdb->get_var( + "SELECT COUNT(*) FROM {$wpdb->options} WHERE option_name LIKE 'woonoow_mail_%'" +); + +if ($still_queued == 0) { + echo " โ All emails sent (queue is empty)\n"; +} else { + echo " โ Still $still_queued email(s) in queue\n"; +} + +// Test 7: Direct wp_mail test +echo "\n7. Testing wp_mail() directly...\n"; +$direct_result = wp_mail( + get_option('admin_email'), + 'Direct wp_mail Test - ' . date('H:i:s'), + 'This bypasses the queue entirely.
', + ['Content-Type: text/html; charset=UTF-8'] +); + +echo " wp_mail() returned: " . ($direct_result ? 'TRUE (success)' : 'FALSE (failed)') . "\n"; + +if (!$direct_result) { + echo " โ wp_mail() failed - check your SMTP configuration\n"; +} else { + echo " โ wp_mail() succeeded - check your inbox\n"; +} + +echo "\n=== Test Complete ===\n"; +echo "Check /wp-content/debug.log for detailed logs\n"; +echo "Check Email Log plugin for sent emails\n";