docs: Consolidate documentation - 52% reduction (56 → 27 files)
✅ Documentation Cleanup: - Deleted 30 obsolete/completed docs - Created NOTIFICATION_SYSTEM.md (consolidates all notification docs) - Reduced from 56 to 27 MD files (52% reduction) 🗑️ Removed Categories: - Completed features (ALL_ISSUES_FIXED, BASIC_CARD_COMPLETE, etc.) - Superseded plans (NOTIFICATION_STRATEGY, NOTIFICATION_REFACTOR_*, etc.) - Duplicate/fragmented docs (MARKDOWN_*, TEMPLATE_*, etc.) 📝 Consolidated: - All notification documentation → NOTIFICATION_SYSTEM.md - Architecture & flow - Markdown syntax reference - Variables reference - Backend integration details - API endpoints - Email queue system - Global system toggle - Q&A section ✅ Kept Essential Docs (27): - Core architecture guides - Addon development guides - Feature-specific docs (shipping, payment, tax) - Implementation guides (i18n, hooks) - Project docs (README, PROJECT_BRIEF, PROJECT_SOP) 📊 Result: - Clearer navigation - Less confusion - Single source of truth for notifications - Easier for new developers
This commit is contained in:
@@ -1,299 +0,0 @@
|
|||||||
# ✅ ALL 4 ISSUES FIXED - Complete System Overhaul
|
|
||||||
|
|
||||||
## 🔴 Issues You Reported
|
|
||||||
|
|
||||||
1. ❌ Customer showing 7 templates instead of 9 (missing "Registered" and "VIP Upgraded")
|
|
||||||
2. ❌ Card types missing (all showing `[card]` instead of `[card type="hero"]`)
|
|
||||||
3. ❌ Preview showing raw markdown (not converting to HTML)
|
|
||||||
4. ❌ Button text and syntax highlighting issues
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✅ Root Causes Found & Fixed
|
|
||||||
|
|
||||||
### **Issue #1: Missing Customer Templates**
|
|
||||||
|
|
||||||
**Root Cause:**
|
|
||||||
```php
|
|
||||||
// DefaultEmailTemplates.php - WRONG mapping!
|
|
||||||
'customer_registered' => 'customer_registered', // ❌ Wrong key!
|
|
||||||
'customer_vip_upgraded' => 'customer_vip_upgraded', // ❌ Wrong key!
|
|
||||||
|
|
||||||
// But DefaultTemplates.php uses:
|
|
||||||
'registered' => self::customer_registered(), // ✅ Correct key
|
|
||||||
'vip_upgraded' => self::customer_vip_upgraded(), // ✅ Correct key
|
|
||||||
```
|
|
||||||
|
|
||||||
**The Problem:**
|
|
||||||
- `DefaultTemplates.php` uses keys: `'registered'` and `'vip_upgraded'`
|
|
||||||
- `DefaultEmailTemplates.php` was mapping to: `'customer_registered'` and `'customer_vip_upgraded'`
|
|
||||||
- **Mismatch!** Templates not found, so only 7 showed instead of 9
|
|
||||||
|
|
||||||
**Fix Applied:**
|
|
||||||
```php
|
|
||||||
// File: includes/Core/Notifications/DefaultEmailTemplates.php
|
|
||||||
// Lines 37-40
|
|
||||||
|
|
||||||
'new_customer' => 'registered', // ✅ Fixed!
|
|
||||||
'customer_registered' => 'registered', // ✅ Fixed!
|
|
||||||
'customer_vip_upgraded' => 'vip_upgraded', // ✅ Fixed!
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **Issue #2: Card Types Missing**
|
|
||||||
|
|
||||||
**Root Cause:**
|
|
||||||
```typescript
|
|
||||||
// markdownToBlocks() regex wasn't trimming attributes
|
|
||||||
const attributes = cardMatch[1]; // " type=\"hero\"" with leading space
|
|
||||||
const typeMatch = attributes.match(/type=["']([^"']+)["']/); // ❌ Fails!
|
|
||||||
```
|
|
||||||
|
|
||||||
**Fix Applied:**
|
|
||||||
```typescript
|
|
||||||
// File: admin-spa/src/components/EmailBuilder/converter.ts
|
|
||||||
// Lines 230-235
|
|
||||||
|
|
||||||
const attributes = cardMatch[1].trim(); // ✅ Trim first!
|
|
||||||
const typeMatch = attributes.match(/type\s*=\s*["']([^"']+)["']/); // ✅ Handle spaces!
|
|
||||||
const cardType = (typeMatch?.[1] || 'default') as CardType;
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **Issue #3: Preview Showing Raw Markdown**
|
|
||||||
|
|
||||||
**Root Cause:**
|
|
||||||
```typescript
|
|
||||||
// Preview was showing markdown like "# heading" instead of "<h1>heading</h1>"
|
|
||||||
// parseCardsForPreview() wasn't converting markdown to HTML
|
|
||||||
return `<div class="${cardClass}">${cardContent}</div>`; // ❌ Raw markdown!
|
|
||||||
```
|
|
||||||
|
|
||||||
**Fix Applied:**
|
|
||||||
```typescript
|
|
||||||
// File: admin-spa/src/routes/Settings/Notifications/EditTemplate.tsx
|
|
||||||
// Lines 224-227
|
|
||||||
|
|
||||||
// Convert markdown inside card to HTML
|
|
||||||
const htmlContent = markdownToHtml(cardContent.trim()); // ✅ Convert!
|
|
||||||
return `<div class="${cardClass}" style="${bgStyle}">${htmlContent}</div>`;
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **Issue #4: Button Text & Labels**
|
|
||||||
|
|
||||||
**Root Cause:**
|
|
||||||
- Button text was too short ("Markdown" vs "Switch to Markdown")
|
|
||||||
- Tab label didn't change when in markdown mode
|
|
||||||
|
|
||||||
**Fix Applied:**
|
|
||||||
```typescript
|
|
||||||
// File: admin-spa/src/routes/Settings/Notifications/EditTemplate.tsx
|
|
||||||
// Lines 534, 542
|
|
||||||
|
|
||||||
<Label>{markdownMode ? __('Markdown') : __('Message Body')}</Label> // ✅ Dynamic label!
|
|
||||||
|
|
||||||
<Button>
|
|
||||||
{markdownMode ? __('Switch to Visual Builder') : __('Switch to Markdown')} // ✅ Clear text!
|
|
||||||
</Button>
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📊 Before vs After
|
|
||||||
|
|
||||||
### **Before (Broken):**
|
|
||||||
```
|
|
||||||
Customer Templates: 7 (missing 2)
|
|
||||||
Card Display: [card] (no type)
|
|
||||||
Preview: # New order received! (raw markdown)
|
|
||||||
Button: "Markdown" (confusing)
|
|
||||||
```
|
|
||||||
|
|
||||||
### **After (Fixed):**
|
|
||||||
```
|
|
||||||
Customer Templates: 9 ✅ (all showing)
|
|
||||||
Card Display: [card type="hero"] ✅ (type preserved)
|
|
||||||
Preview: <h1>New order received!</h1> ✅ (rendered HTML)
|
|
||||||
Button: "Switch to Markdown" ✅ (clear)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔄 Complete Data Flow (Now Working!)
|
|
||||||
|
|
||||||
### **Loading Template:**
|
|
||||||
```
|
|
||||||
1. Database → Markdown template
|
|
||||||
2. markdownToBlocks() → Parse with card types ✅
|
|
||||||
3. blocksToMarkdown() → Clean markdown ✅
|
|
||||||
4. Preview: markdownToHtml() → Rendered HTML ✅
|
|
||||||
```
|
|
||||||
|
|
||||||
### **Visual Mode:**
|
|
||||||
```
|
|
||||||
User edits blocks
|
|
||||||
↓
|
|
||||||
handleBlocksChange()
|
|
||||||
↓
|
|
||||||
├→ blocksToHTML() → HTML (for saving)
|
|
||||||
└→ blocksToMarkdown() → Markdown (synced)
|
|
||||||
↓
|
|
||||||
✅ All synced, types preserved!
|
|
||||||
```
|
|
||||||
|
|
||||||
### **Markdown Mode:**
|
|
||||||
```
|
|
||||||
User types markdown
|
|
||||||
↓
|
|
||||||
handleMarkdownChange()
|
|
||||||
↓
|
|
||||||
├→ markdownToBlocks() → Parse types ✅
|
|
||||||
└→ blocksToHTML() → HTML (for saving)
|
|
||||||
↓
|
|
||||||
✅ All synced, types preserved!
|
|
||||||
```
|
|
||||||
|
|
||||||
### **Preview:**
|
|
||||||
```
|
|
||||||
htmlContent (with [card] shortcodes)
|
|
||||||
↓
|
|
||||||
parseCardsForPreview()
|
|
||||||
↓
|
|
||||||
├→ Extract card type ✅
|
|
||||||
├→ Convert markdown to HTML ✅
|
|
||||||
└→ Generate styled <div> ✅
|
|
||||||
↓
|
|
||||||
✅ Beautiful preview!
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📁 Files Modified
|
|
||||||
|
|
||||||
### **1. DefaultTemplates.php**
|
|
||||||
**Lines:** 42-43
|
|
||||||
**Change:** Fixed template keys from `'customer_registered'` to `'registered'`
|
|
||||||
**Impact:** Customer now shows 9 templates ✅
|
|
||||||
|
|
||||||
### **2. DefaultEmailTemplates.php**
|
|
||||||
**Lines:** 37-40
|
|
||||||
**Change:** Fixed event mapping to use correct keys
|
|
||||||
**Impact:** Templates now found correctly ✅
|
|
||||||
|
|
||||||
### **3. converter.ts**
|
|
||||||
**Lines:** 230-235
|
|
||||||
**Change:** Trim attributes and handle spaces in regex
|
|
||||||
**Impact:** Card types now parsed correctly ✅
|
|
||||||
|
|
||||||
### **4. EditTemplate.tsx**
|
|
||||||
**Lines:** 224-227, 534, 542
|
|
||||||
**Changes:**
|
|
||||||
- Convert markdown to HTML in preview
|
|
||||||
- Update button text to be clearer
|
|
||||||
- Dynamic tab label
|
|
||||||
**Impact:** Preview works, UI is clearer ✅
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🧪 Testing Checklist
|
|
||||||
|
|
||||||
### ✅ Test 1: Customer Templates Count
|
|
||||||
1. Go to Customer Notifications
|
|
||||||
2. Expand Email channel
|
|
||||||
3. **Expected:** 9 templates showing
|
|
||||||
4. **Result:** ✅ PASS
|
|
||||||
|
|
||||||
### ✅ Test 2: Card Types Preserved
|
|
||||||
1. Open "Order Placed" template
|
|
||||||
2. Check first card in Visual Builder
|
|
||||||
3. **Expected:** Card type = "hero"
|
|
||||||
4. **Result:** ✅ PASS
|
|
||||||
|
|
||||||
### ✅ Test 3: Preview Rendering
|
|
||||||
1. Open any template
|
|
||||||
2. Click "Preview" tab
|
|
||||||
3. **Expected:** Headings rendered as HTML, not markdown
|
|
||||||
4. **Result:** ✅ PASS
|
|
||||||
|
|
||||||
### ✅ Test 4: Markdown Mode
|
|
||||||
1. Click "Switch to Markdown"
|
|
||||||
2. **Expected:** Clean markdown, button says "Switch to Visual Builder"
|
|
||||||
3. **Result:** ✅ PASS
|
|
||||||
|
|
||||||
### ✅ Test 5: Mode Switching
|
|
||||||
1. Visual → Markdown → Visual → Markdown
|
|
||||||
2. **Expected:** No data loss, types preserved
|
|
||||||
3. **Result:** ✅ PASS
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 What Was The Real Problem?
|
|
||||||
|
|
||||||
### **The Core Issue:**
|
|
||||||
We had **THREE DIFFERENT SYSTEMS** trying to work together:
|
|
||||||
1. `DefaultTemplates.php` - New markdown templates (uses `'registered'` key)
|
|
||||||
2. `DefaultEmailTemplates.php` - Legacy wrapper (was using `'customer_registered'` key)
|
|
||||||
3. `TemplateProvider.php` - Template fetcher (relies on exact key match)
|
|
||||||
|
|
||||||
**Key mismatch = Templates not found!**
|
|
||||||
|
|
||||||
### **The Solution:**
|
|
||||||
- **Aligned all keys** across the system
|
|
||||||
- **Fixed parsing** to handle attributes correctly
|
|
||||||
- **Added markdown conversion** in preview
|
|
||||||
- **Improved UI** for clarity
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 💡 Why This Happened
|
|
||||||
|
|
||||||
### **Historical Context:**
|
|
||||||
1. Originally: HTML-based templates
|
|
||||||
2. Refactored: Markdown-based templates in `DefaultTemplates.php`
|
|
||||||
3. Wrapper: `DefaultEmailTemplates.php` created for compatibility
|
|
||||||
4. **Problem:** Wrapper used wrong keys!
|
|
||||||
|
|
||||||
### **The Cascade Effect:**
|
|
||||||
```
|
|
||||||
Wrong key in wrapper
|
|
||||||
↓
|
|
||||||
Template not found
|
|
||||||
↓
|
|
||||||
Fallback to default
|
|
||||||
↓
|
|
||||||
Only 7 templates show (missing 2)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚀 Next Steps
|
|
||||||
|
|
||||||
1. **Stop dev server** (Ctrl+C)
|
|
||||||
2. **Restart:** `npm run dev`
|
|
||||||
3. **Hard refresh browser:** Cmd+Shift+R
|
|
||||||
4. **Test all 4 issues:**
|
|
||||||
- ✅ Customer shows 9 templates
|
|
||||||
- ✅ Card types preserved
|
|
||||||
- ✅ Preview renders HTML
|
|
||||||
- ✅ Markdown mode works
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📝 Summary
|
|
||||||
|
|
||||||
| Issue | Root Cause | Fix | Status |
|
|
||||||
|-------|------------|-----|--------|
|
|
||||||
| **Missing templates** | Key mismatch | Aligned keys | ✅ FIXED |
|
|
||||||
| **Card types missing** | Regex not trimming | Trim + better regex | ✅ FIXED |
|
|
||||||
| **Raw markdown in preview** | No conversion | Added markdownToHtml() | ✅ FIXED |
|
|
||||||
| **Confusing UI** | Short button text | Clear labels | ✅ FIXED |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**🎉 ALL ISSUES RESOLVED! The system is now working as designed!**
|
|
||||||
|
|
||||||
**Test it now - everything should work perfectly!** 🚀
|
|
||||||
@@ -1,268 +0,0 @@
|
|||||||
# ⚠️ Backend Integration Required
|
|
||||||
|
|
||||||
## Issues Found
|
|
||||||
|
|
||||||
### Issue #1: Incorrect Template Count in UI ❌
|
|
||||||
|
|
||||||
**Problem:**
|
|
||||||
The Staff Notifications page shows "9 templates" but there are only **7 staff events**.
|
|
||||||
|
|
||||||
**Location:**
|
|
||||||
`admin-spa/src/routes/Settings/Notifications/Templates.tsx` line 132
|
|
||||||
|
|
||||||
**Current Code:**
|
|
||||||
```tsx
|
|
||||||
<Badge variant="secondary" className="text-xs">
|
|
||||||
{allEvents.length} {__('templates')} // ❌ Shows ALL events (customer + staff)
|
|
||||||
</Badge>
|
|
||||||
```
|
|
||||||
|
|
||||||
**Root Cause:**
|
|
||||||
- `allEvents` combines ALL event types (orders, products, customers)
|
|
||||||
- It doesn't filter by recipient type (staff vs customer)
|
|
||||||
- Shows same count for both customer and staff pages
|
|
||||||
|
|
||||||
**Expected:**
|
|
||||||
- **Customer page:** Should show 9 templates (customer events only)
|
|
||||||
- **Staff page:** Should show 7 templates (staff events only)
|
|
||||||
|
|
||||||
**Solution Needed:**
|
|
||||||
The backend API `/notifications/events` needs to return events grouped by recipient type, OR the frontend needs to filter events based on the current page (staff/customer).
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Issue #2: Old Templates Still Being Used ❌
|
|
||||||
|
|
||||||
**Problem:**
|
|
||||||
After reloading multiple times, the email templates shown in the editor are still using the OLD format, not the new improved markdown templates.
|
|
||||||
|
|
||||||
**Current State:**
|
|
||||||
- ✅ New templates exist: `includes/Email/DefaultTemplates.php`
|
|
||||||
- ❌ Backend still using: `includes/Core/Notifications/DefaultEmailTemplates.php`
|
|
||||||
|
|
||||||
**Evidence:**
|
|
||||||
The old `DefaultEmailTemplates.php` uses HTML-heavy syntax:
|
|
||||||
```php
|
|
||||||
'body' => '[card type="hero"]
|
|
||||||
<h1>' . __('New Order Received!', 'woonoow') . '</h1>
|
|
||||||
<p>' . __('You have received a new order...', 'woonoow') . '</p>
|
|
||||||
[/card]'
|
|
||||||
```
|
|
||||||
|
|
||||||
The new `DefaultTemplates.php` uses clean markdown:
|
|
||||||
```php
|
|
||||||
return '[card type="hero"]
|
|
||||||
|
|
||||||
New order received!
|
|
||||||
|
|
||||||
A customer has placed a new order. Please review and process.
|
|
||||||
[/card]'
|
|
||||||
```
|
|
||||||
|
|
||||||
**Root Cause:**
|
|
||||||
The backend API controller is still calling the old `DefaultEmailTemplates` class instead of the new `DefaultTemplates` class.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Required Backend Changes
|
|
||||||
|
|
||||||
### 1. Update Default Templates Integration
|
|
||||||
|
|
||||||
**Option A: Replace Old Class (Recommended)**
|
|
||||||
|
|
||||||
Replace `includes/Core/Notifications/DefaultEmailTemplates.php` with a wrapper that uses the new class:
|
|
||||||
|
|
||||||
```php
|
|
||||||
<?php
|
|
||||||
namespace WooNooW\Core\Notifications;
|
|
||||||
|
|
||||||
use WooNooW\Email\DefaultTemplates as NewDefaultTemplates;
|
|
||||||
|
|
||||||
class DefaultEmailTemplates {
|
|
||||||
|
|
||||||
public static function get_template($event_id, $recipient_type) {
|
|
||||||
// Map event IDs to new template structure
|
|
||||||
$eventMap = [
|
|
||||||
'order_placed' => 'order_placed',
|
|
||||||
'order_processing' => 'order_confirmed',
|
|
||||||
'order_completed' => 'order_completed',
|
|
||||||
'order_cancelled' => 'order_cancelled',
|
|
||||||
'order_refunded' => 'order_cancelled', // Map to cancelled for now
|
|
||||||
'low_stock' => 'order_placed', // Placeholder
|
|
||||||
'out_of_stock' => 'order_placed', // Placeholder
|
|
||||||
'new_customer' => 'customer_registered',
|
|
||||||
'customer_note' => 'order_placed', // Placeholder
|
|
||||||
];
|
|
||||||
|
|
||||||
$newEventId = $eventMap[$event_id] ?? $event_id;
|
|
||||||
|
|
||||||
// Get templates from new class
|
|
||||||
$allTemplates = NewDefaultTemplates::get_all_templates();
|
|
||||||
$templates = $allTemplates[$recipient_type] ?? [];
|
|
||||||
|
|
||||||
if (isset($templates[$newEventId])) {
|
|
||||||
return [
|
|
||||||
'subject' => NewDefaultTemplates::get_default_subject($recipient_type, $newEventId),
|
|
||||||
'body' => $templates[$newEventId],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback
|
|
||||||
return [
|
|
||||||
'subject' => __('Notification from {store_name}', 'woonoow'),
|
|
||||||
'body' => '[card]New notification[/card]',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Option B: Update API Controller Directly**
|
|
||||||
|
|
||||||
Update the API controller to use the new `DefaultTemplates` class:
|
|
||||||
|
|
||||||
```php
|
|
||||||
use WooNooW\Email\DefaultTemplates;
|
|
||||||
|
|
||||||
// In the get_template endpoint:
|
|
||||||
$templates = DefaultTemplates::get_all_templates();
|
|
||||||
$subject = DefaultTemplates::get_default_subject($recipient_type, $event_id);
|
|
||||||
$body = $templates[$recipient_type][$event_id] ?? '';
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2. Fix Event Counts in API
|
|
||||||
|
|
||||||
**Update:** `includes/Api/NotificationsController.php`
|
|
||||||
|
|
||||||
The `/notifications/events` endpoint should return events with recipient type information:
|
|
||||||
|
|
||||||
```php
|
|
||||||
public function get_events($request) {
|
|
||||||
$events = [
|
|
||||||
'orders' => [
|
|
||||||
[
|
|
||||||
'id' => 'order_placed',
|
|
||||||
'label' => __('Order Placed'),
|
|
||||||
'description' => __('When a new order is placed'),
|
|
||||||
'recipients' => ['customer', 'staff'], // ← Add this
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'id' => 'order_confirmed',
|
|
||||||
'label' => __('Order Confirmed'),
|
|
||||||
'description' => __('When order is confirmed'),
|
|
||||||
'recipients' => ['customer', 'staff'], // ← Add this
|
|
||||||
],
|
|
||||||
// ... etc
|
|
||||||
],
|
|
||||||
'customers' => [
|
|
||||||
[
|
|
||||||
'id' => 'customer_registered',
|
|
||||||
'label' => __('Customer Registered'),
|
|
||||||
'description' => __('When customer creates account'),
|
|
||||||
'recipients' => ['customer'], // ← Customer only
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'id' => 'customer_vip_upgraded',
|
|
||||||
'label' => __('VIP Upgraded'),
|
|
||||||
'description' => __('When customer becomes VIP'),
|
|
||||||
'recipients' => ['customer'], // ← Customer only
|
|
||||||
],
|
|
||||||
],
|
|
||||||
];
|
|
||||||
|
|
||||||
return rest_ensure_response($events);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3. Update Frontend to Filter Events
|
|
||||||
|
|
||||||
**Update:** `admin-spa/src/routes/Settings/Notifications/Templates.tsx`
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
// Determine recipient type from current page
|
|
||||||
const isStaffPage = window.location.pathname.includes('/staff');
|
|
||||||
const recipientType = isStaffPage ? 'staff' : 'customer';
|
|
||||||
|
|
||||||
// Filter events by recipient
|
|
||||||
const filteredEvents = allEvents.filter((event: any) => {
|
|
||||||
return event.recipients && event.recipients.includes(recipientType);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Use filteredEvents instead of allEvents
|
|
||||||
<Badge variant="secondary" className="text-xs">
|
|
||||||
{filteredEvents.length} {__('templates')}
|
|
||||||
</Badge>
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Event Mapping
|
|
||||||
|
|
||||||
### Customer Events (9 total)
|
|
||||||
1. `order_placed` → Order Placed
|
|
||||||
2. `order_confirmed` → Order Confirmed
|
|
||||||
3. `order_shipped` → Order Shipped
|
|
||||||
4. `order_completed` → Order Completed
|
|
||||||
5. `order_cancelled` → Order Cancelled
|
|
||||||
6. `payment_received` → Payment Received
|
|
||||||
7. `payment_failed` → Payment Failed
|
|
||||||
8. `customer_registered` → Customer Registered
|
|
||||||
9. `customer_vip_upgraded` → VIP Upgraded
|
|
||||||
|
|
||||||
### Staff Events (7 total)
|
|
||||||
1. `order_placed` → New Order
|
|
||||||
2. `order_confirmed` → Order Confirmed
|
|
||||||
3. `order_shipped` → Order Shipped
|
|
||||||
4. `order_completed` → Order Completed
|
|
||||||
5. `order_cancelled` → Order Cancelled
|
|
||||||
6. `payment_received` → Payment Received
|
|
||||||
7. `payment_failed` → Payment Failed
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Testing Checklist
|
|
||||||
|
|
||||||
After backend integration:
|
|
||||||
|
|
||||||
- [ ] Navigate to Customer Notifications → Templates
|
|
||||||
- [ ] Verify "9 templates" badge shows
|
|
||||||
- [ ] Open any customer event template
|
|
||||||
- [ ] Verify new markdown format is shown (not HTML)
|
|
||||||
- [ ] Navigate to Staff Notifications → Templates
|
|
||||||
- [ ] Verify "7 templates" badge shows
|
|
||||||
- [ ] Open any staff event template
|
|
||||||
- [ ] Verify new markdown format is shown
|
|
||||||
- [ ] Test saving a template
|
|
||||||
- [ ] Test resetting a template to default
|
|
||||||
- [ ] Verify preview shows correct formatting
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Priority
|
|
||||||
|
|
||||||
**HIGH PRIORITY** - These issues prevent the new templates from being used and show incorrect information to users.
|
|
||||||
|
|
||||||
**Estimated Time:** 1-2 hours to implement and test
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
**What Works:**
|
|
||||||
- ✅ Frontend email builder
|
|
||||||
- ✅ Markdown parser
|
|
||||||
- ✅ Preview system
|
|
||||||
- ✅ New template files created
|
|
||||||
|
|
||||||
**What Needs Fixing:**
|
|
||||||
- ❌ Backend not using new templates
|
|
||||||
- ❌ Template count incorrect in UI
|
|
||||||
- ❌ Event-to-recipient mapping needed
|
|
||||||
|
|
||||||
**Once Fixed:**
|
|
||||||
- ✅ Users will see new improved templates
|
|
||||||
- ✅ Correct template counts
|
|
||||||
- ✅ Better UX overall
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
# Backend Wiring Complete ✅
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
All notification system components are fully wired and functional.
|
|
||||||
|
|
||||||
## What's Wired
|
|
||||||
|
|
||||||
### 1. Template System ✅
|
|
||||||
- Save/Get templates via API
|
|
||||||
- EmailRenderer uses templates
|
|
||||||
- Variables replaced automatically
|
|
||||||
- Markdown parsed (cards, buttons, images)
|
|
||||||
|
|
||||||
### 2. Channel Toggles ✅
|
|
||||||
- Frontend toggles saved to database
|
|
||||||
- NotificationManager checks before sending
|
|
||||||
- Email: `woonoow_email_notifications_enabled`
|
|
||||||
- Push: `woonoow_push_notifications_enabled`
|
|
||||||
|
|
||||||
### 3. Event Toggles ✅
|
|
||||||
- Per-event channel settings saved
|
|
||||||
- Stored in `woonoow_notification_settings`
|
|
||||||
- Checked before sending notifications
|
|
||||||
|
|
||||||
### 4. Global System Toggle ✅
|
|
||||||
- NEW: Switch between WooNooW and WooCommerce
|
|
||||||
- API: `GET/POST /notifications/system-mode`
|
|
||||||
- Stored in: `woonoow_notification_system_mode`
|
|
||||||
- EmailManager respects this setting
|
|
||||||
- NotificationManager checks before sending
|
|
||||||
|
|
||||||
### 5. Email Customization ✅
|
|
||||||
- Colors, logo, branding saved
|
|
||||||
- EmailRenderer applies customization
|
|
||||||
- Stored in: `woonoow_email_settings`
|
|
||||||
|
|
||||||
### 6. Push Settings ✅
|
|
||||||
- Icon, badge, sound settings
|
|
||||||
- PushNotificationHandler applies settings
|
|
||||||
|
|
||||||
## Notification Flow
|
|
||||||
|
|
||||||
```
|
|
||||||
Event → EmailManager → Check System Mode → Check Channel Toggle
|
|
||||||
→ Check Event Toggle → EmailRenderer → Get Template → Replace Variables
|
|
||||||
→ Parse Markdown → Apply Branding → wp_mail() → Sent ✅
|
|
||||||
```
|
|
||||||
|
|
||||||
## Key Files Modified
|
|
||||||
- `NotificationsController.php`: Added system-mode endpoints
|
|
||||||
- `NotificationManager.php`: Added system mode check
|
|
||||||
- `EmailManager.php`: Added is_enabled() check
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
All settings are now saved and applied when sending notifications.
|
|
||||||
@@ -1,228 +0,0 @@
|
|||||||
# ✅ Basic Card Type & Newline Fixes Complete!
|
|
||||||
|
|
||||||
## Problems Solved! 🎉
|
|
||||||
|
|
||||||
1. ✅ **Newlines preserved** - Text no longer collapses into one line
|
|
||||||
2. ✅ **Basic card type added** - Plain text sections without styling
|
|
||||||
3. ✅ **No content loss** - All content can be wrapped in cards
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## What Was Fixed
|
|
||||||
|
|
||||||
### 1. Newline Parsing ✅
|
|
||||||
|
|
||||||
**Problem:** Markdown newlines were collapsed, making everything inline
|
|
||||||
|
|
||||||
**Solution:** Updated `markdown-utils.ts` to:
|
|
||||||
- Preserve paragraph breaks (double newlines)
|
|
||||||
- Add `<br>` tags for single newlines within paragraphs
|
|
||||||
- Properly close and open `<p>` tags
|
|
||||||
|
|
||||||
**Result:**
|
|
||||||
```markdown
|
|
||||||
Order Number: #12345
|
|
||||||
Customer: John Doe
|
|
||||||
```
|
|
||||||
Now renders as:
|
|
||||||
```html
|
|
||||||
<p>
|
|
||||||
Order Number: #12345<br>
|
|
||||||
Customer: John Doe
|
|
||||||
</p>
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2. Basic Card Type ✅
|
|
||||||
|
|
||||||
**What It Is:**
|
|
||||||
- A new card type: `[card type="basic"]`
|
|
||||||
- **No background** color
|
|
||||||
- **No border**
|
|
||||||
- **No padding**
|
|
||||||
- Just plain text in a section
|
|
||||||
|
|
||||||
**Why It's Useful:**
|
|
||||||
- Wrap footer text without styling
|
|
||||||
- Ensure all content is in blocks (no loss)
|
|
||||||
- Give users a "plain text" option
|
|
||||||
- Makes templates more structured
|
|
||||||
|
|
||||||
**CSS:**
|
|
||||||
```css
|
|
||||||
.card-basic {
|
|
||||||
background: none;
|
|
||||||
border: none;
|
|
||||||
padding: 0;
|
|
||||||
margin: 16px 0;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3. Template Footer Updates 📝
|
|
||||||
|
|
||||||
**Old Pattern:**
|
|
||||||
```markdown
|
|
||||||
---
|
|
||||||
|
|
||||||
Need help? Contact {support_email}
|
|
||||||
© {current_year} {site_name}
|
|
||||||
```
|
|
||||||
|
|
||||||
**New Pattern:**
|
|
||||||
```markdown
|
|
||||||
[card type="basic"]
|
|
||||||
|
|
||||||
Need help? Contact {support_email}
|
|
||||||
|
|
||||||
[/card]
|
|
||||||
```
|
|
||||||
|
|
||||||
**Changes:**
|
|
||||||
- ✅ Removed `© {current_year} {site_name}` (already in global footer)
|
|
||||||
- ✅ Wrapped support text in `[card type="basic"]`
|
|
||||||
- ✅ Removed standalone `---` separators
|
|
||||||
- ✅ Staff templates: Removed footer entirely
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Files Modified
|
|
||||||
|
|
||||||
### 1. **`admin-spa/src/lib/markdown-utils.ts`**
|
|
||||||
- Fixed newline handling
|
|
||||||
- Proper paragraph and line break parsing
|
|
||||||
- Better list handling
|
|
||||||
|
|
||||||
### 2. **`admin-spa/src/components/EmailBuilder/types.ts`**
|
|
||||||
- Added `'basic'` to `CardType`
|
|
||||||
|
|
||||||
### 3. **`admin-spa/src/components/EmailBuilder/EmailBuilder.tsx`**
|
|
||||||
- Added "Basic (Plain Text)" option to card type selector
|
|
||||||
|
|
||||||
### 4. **`admin-spa/src/routes/Settings/Notifications/EditTemplate.tsx`**
|
|
||||||
- Added CSS for `.card-basic` (no styling)
|
|
||||||
|
|
||||||
### 5. **`includes/Email/DefaultTemplates.php`** (needs manual update)
|
|
||||||
- See `TEMPLATE_UPDATE_SCRIPT.md` for all changes
|
|
||||||
- 17 templates need footer updates
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## How Basic Card Works
|
|
||||||
|
|
||||||
### In Markdown:
|
|
||||||
```markdown
|
|
||||||
[card type="basic"]
|
|
||||||
|
|
||||||
This is plain text.
|
|
||||||
No background, no border, no padding.
|
|
||||||
|
|
||||||
Just content.
|
|
||||||
|
|
||||||
[/card]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Renders As:
|
|
||||||
```html
|
|
||||||
<div class="card card-basic">
|
|
||||||
<p>This is plain text.<br>
|
|
||||||
No background, no border, no padding.</p>
|
|
||||||
<p>Just content.</p>
|
|
||||||
</div>
|
|
||||||
```
|
|
||||||
|
|
||||||
### Displays As:
|
|
||||||
```
|
|
||||||
This is plain text.
|
|
||||||
No background, no border, no padding.
|
|
||||||
|
|
||||||
Just content.
|
|
||||||
```
|
|
||||||
(No visual styling - just text!)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Benefits
|
|
||||||
|
|
||||||
### ✅ For Content:
|
|
||||||
- All content wrapped in blocks
|
|
||||||
- No content loss in converter
|
|
||||||
- Structured templates
|
|
||||||
|
|
||||||
### ✅ For Users:
|
|
||||||
- Can add plain text sections
|
|
||||||
- No forced styling
|
|
||||||
- More flexible templates
|
|
||||||
|
|
||||||
### ✅ For Developers:
|
|
||||||
- Cleaner template structure
|
|
||||||
- Easier to parse
|
|
||||||
- Better maintainability
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Card Type Comparison
|
|
||||||
|
|
||||||
| Type | Background | Border | Padding | Use Case |
|
|
||||||
|------|------------|--------|---------|----------|
|
|
||||||
| **basic** | None | None | None | Plain text, footers |
|
|
||||||
| **default** | White | Gray | Yes | Standard content |
|
|
||||||
| **hero** | Gradient | None | Yes | Headers, highlights |
|
|
||||||
| **success** | Gradient | None | Yes | Confirmations |
|
|
||||||
| **info** | Light blue | Blue | Yes | Information |
|
|
||||||
| **warning** | Light yellow | Orange | Yes | Warnings |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Next Steps
|
|
||||||
|
|
||||||
### Manual Template Updates Required:
|
|
||||||
|
|
||||||
You need to update `includes/Email/DefaultTemplates.php`:
|
|
||||||
|
|
||||||
1. Open the file
|
|
||||||
2. Follow `TEMPLATE_UPDATE_SCRIPT.md`
|
|
||||||
3. Update all 17 template footers
|
|
||||||
4. Remove copyright lines
|
|
||||||
5. Wrap support text in `[card type="basic"]`
|
|
||||||
|
|
||||||
**Estimated time:** 10-15 minutes
|
|
||||||
|
|
||||||
**Or:** I can help you do it programmatically if you prefer!
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Testing Checklist
|
|
||||||
|
|
||||||
### ✅ Newlines:
|
|
||||||
- [x] Text with newlines displays correctly
|
|
||||||
- [x] Paragraphs separated properly
|
|
||||||
- [x] Line breaks within paragraphs work
|
|
||||||
|
|
||||||
### ✅ Basic Card:
|
|
||||||
- [x] Can select "Basic (Plain Text)" in editor
|
|
||||||
- [x] No background/border/padding applied
|
|
||||||
- [x] Content displays as plain text
|
|
||||||
- [x] Works in preview
|
|
||||||
|
|
||||||
### ✅ Templates:
|
|
||||||
- [ ] Update all template footers
|
|
||||||
- [ ] Test customer templates
|
|
||||||
- [ ] Test staff templates
|
|
||||||
- [ ] Verify no content loss
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
| Feature | Status |
|
|
||||||
|---------|--------|
|
|
||||||
| Newline parsing | ✅ Fixed |
|
|
||||||
| Basic card type | ✅ Added |
|
|
||||||
| Card type selector | ✅ Updated |
|
|
||||||
| Preview CSS | ✅ Updated |
|
|
||||||
| Template updates | 📝 Manual needed |
|
|
||||||
|
|
||||||
**Almost done! Just need to update the template footers! 🚀**
|
|
||||||
@@ -1,402 +0,0 @@
|
|||||||
# ✅ CLEAN MARKDOWN - NO MORE HTML POLLUTION! 🎉
|
|
||||||
|
|
||||||
## Problem Identified & Fixed!
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔴 The Problem You Reported
|
|
||||||
|
|
||||||
### **What You Saw:**
|
|
||||||
1. Click "Markdown" button
|
|
||||||
2. See HTML code with `<p>` and `<br>` tags ❌
|
|
||||||
3. Mixed HTML + markdown syntax (messy!)
|
|
||||||
4. Switch back to visual → More `<p>` and `<br>` added
|
|
||||||
5. **Endless pollution!** ❌
|
|
||||||
|
|
||||||
### **Root Cause:**
|
|
||||||
```typescript
|
|
||||||
// OLD (BROKEN) FLOW:
|
|
||||||
Visual Builder (blocks)
|
|
||||||
↓
|
|
||||||
blocksToHTML() → Adds <p> and <br>
|
|
||||||
↓
|
|
||||||
htmlToMarkdown() → Tries to clean, but messy
|
|
||||||
↓
|
|
||||||
"Markdown mode" shows: <p>, <br>, mixed syntax ❌
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✅ The Solution
|
|
||||||
|
|
||||||
### **New Clean Flow:**
|
|
||||||
```typescript
|
|
||||||
// NEW (FIXED) FLOW:
|
|
||||||
Visual Builder (blocks)
|
|
||||||
↓
|
|
||||||
blocksToMarkdown() → Direct conversion!
|
|
||||||
↓
|
|
||||||
Markdown mode shows: Clean markdown ✅
|
|
||||||
```
|
|
||||||
|
|
||||||
### **Key Insight:**
|
|
||||||
**Skip HTML entirely when converting blocks ↔ markdown!**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🛠️ What Was Built
|
|
||||||
|
|
||||||
### **1. New Function: `blocksToMarkdown()`**
|
|
||||||
```typescript
|
|
||||||
// Direct conversion: Blocks → Markdown (no HTML!)
|
|
||||||
export function blocksToMarkdown(blocks: EmailBlock[]): string {
|
|
||||||
return blocks.map(block => {
|
|
||||||
switch (block.type) {
|
|
||||||
case 'card':
|
|
||||||
return `[card type="${block.cardType}"]\n\n${block.content}\n\n[/card]`;
|
|
||||||
case 'button':
|
|
||||||
return `[button url="${block.link}"]${block.text}[/button]`;
|
|
||||||
case 'divider':
|
|
||||||
return '---';
|
|
||||||
// ... etc
|
|
||||||
}
|
|
||||||
}).join('\n\n');
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Result:** Clean markdown, no `<p>`, no `<br>`! ✅
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **2. New Function: `markdownToBlocks()`**
|
|
||||||
```typescript
|
|
||||||
// Direct conversion: Markdown → Blocks (no HTML!)
|
|
||||||
export function markdownToBlocks(markdown: string): EmailBlock[] {
|
|
||||||
const blocks: EmailBlock[] = [];
|
|
||||||
|
|
||||||
// Parse [card] blocks
|
|
||||||
const cardMatch = markdown.match(/\[card([^\]]*)\]([\s\S]*)\[\/card\]/);
|
|
||||||
if (cardMatch) {
|
|
||||||
blocks.push({
|
|
||||||
type: 'card',
|
|
||||||
cardType: extractType(cardMatch[1]),
|
|
||||||
content: cardMatch[2].trim(), // Clean content!
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// ... parse other blocks
|
|
||||||
|
|
||||||
return blocks;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Result:** Direct parsing, no HTML intermediary! ✅
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **3. Updated EditTemplate.tsx**
|
|
||||||
|
|
||||||
#### **Before (BROKEN):**
|
|
||||||
```typescript
|
|
||||||
// Switching to markdown mode
|
|
||||||
const html = blocksToHTML(blocks); // Adds <p>, <br>
|
|
||||||
const markdown = htmlToMarkdown(html); // Messy conversion
|
|
||||||
setMarkdownContent(markdown); // Shows HTML pollution ❌
|
|
||||||
```
|
|
||||||
|
|
||||||
#### **After (FIXED):**
|
|
||||||
```typescript
|
|
||||||
// Switching to markdown mode
|
|
||||||
const markdown = blocksToMarkdown(blocks); // Direct, clean!
|
|
||||||
setMarkdownContent(markdown); // Shows clean markdown ✅
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📊 Comparison
|
|
||||||
|
|
||||||
### **Old Flow (HTML Pollution):**
|
|
||||||
```
|
|
||||||
Visual Builder
|
|
||||||
↓
|
|
||||||
Blocks: { content: "Hello world" }
|
|
||||||
↓
|
|
||||||
blocksToHTML()
|
|
||||||
↓
|
|
||||||
HTML: "<p>Hello world</p>"
|
|
||||||
↓
|
|
||||||
htmlToMarkdown()
|
|
||||||
↓
|
|
||||||
Markdown: "<p>Hello world</p>" ❌ Still has HTML!
|
|
||||||
```
|
|
||||||
|
|
||||||
### **New Flow (Clean Markdown):**
|
|
||||||
```
|
|
||||||
Visual Builder
|
|
||||||
↓
|
|
||||||
Blocks: { content: "Hello world" }
|
|
||||||
↓
|
|
||||||
blocksToMarkdown()
|
|
||||||
↓
|
|
||||||
Markdown: "Hello world" ✅ Clean!
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 What You'll See Now
|
|
||||||
|
|
||||||
### **Markdown Mode (Clean!):**
|
|
||||||
```markdown
|
|
||||||
[card type="hero"]
|
|
||||||
|
|
||||||
# New order received!
|
|
||||||
|
|
||||||
A customer has placed a new order. Please review and process.
|
|
||||||
|
|
||||||
[/card]
|
|
||||||
|
|
||||||
[card]
|
|
||||||
|
|
||||||
**Order Number:** #{order_number}
|
|
||||||
**Customer:** {customer_name}
|
|
||||||
**Order Date:** {order_date}
|
|
||||||
|
|
||||||
[/card]
|
|
||||||
|
|
||||||
[button url="{order_url}"]View Order[/button]
|
|
||||||
```
|
|
||||||
|
|
||||||
**No `<p>`, no `<br>`, just clean markdown!** ✅
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔄 The Complete Data Flow
|
|
||||||
|
|
||||||
### **Loading Template:**
|
|
||||||
```
|
|
||||||
Database (HTML)
|
|
||||||
↓
|
|
||||||
htmlToBlocks() → Blocks
|
|
||||||
↓
|
|
||||||
blocksToMarkdown() → Clean markdown
|
|
||||||
↓
|
|
||||||
✅ Both views ready!
|
|
||||||
```
|
|
||||||
|
|
||||||
### **Visual Mode Editing:**
|
|
||||||
```
|
|
||||||
User edits blocks
|
|
||||||
↓
|
|
||||||
handleBlocksChange()
|
|
||||||
↓
|
|
||||||
├→ blocksToHTML() → HTML (for saving)
|
|
||||||
└→ blocksToMarkdown() → Markdown (for markdown mode)
|
|
||||||
↓
|
|
||||||
✅ Both synced, no pollution!
|
|
||||||
```
|
|
||||||
|
|
||||||
### **Markdown Mode Editing:**
|
|
||||||
```
|
|
||||||
User types markdown
|
|
||||||
↓
|
|
||||||
handleMarkdownChange()
|
|
||||||
↓
|
|
||||||
├→ markdownToBlocks() → Blocks (for visual mode)
|
|
||||||
└→ blocksToHTML() → HTML (for saving)
|
|
||||||
↓
|
|
||||||
✅ Both synced, no pollution!
|
|
||||||
```
|
|
||||||
|
|
||||||
### **Mode Switching:**
|
|
||||||
```
|
|
||||||
Visual → Markdown:
|
|
||||||
blocksToMarkdown(blocks) → Clean markdown ✅
|
|
||||||
|
|
||||||
Markdown → Visual:
|
|
||||||
markdownToBlocks(markdown) → Blocks ✅
|
|
||||||
|
|
||||||
No HTML intermediary = No pollution!
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🧪 Testing Results
|
|
||||||
|
|
||||||
### ✅ Test 1: Visual → Markdown
|
|
||||||
1. Edit in visual mode
|
|
||||||
2. Click "Markdown"
|
|
||||||
3. **Result:** Clean markdown, no `<p>`, no `<br>` ✅
|
|
||||||
|
|
||||||
### ✅ Test 2: Markdown → Visual
|
|
||||||
1. Type clean markdown
|
|
||||||
2. Click "Visual Builder"
|
|
||||||
3. **Result:** Blocks created correctly ✅
|
|
||||||
|
|
||||||
### ✅ Test 3: Multiple Switches
|
|
||||||
1. Visual → Markdown → Visual → Markdown
|
|
||||||
2. **Result:** No pollution accumulation ✅
|
|
||||||
|
|
||||||
### ✅ Test 4: Save & Reload
|
|
||||||
1. Edit in any mode
|
|
||||||
2. Save
|
|
||||||
3. Reload
|
|
||||||
4. **Result:** Clean markdown, no pollution ✅
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📁 Files Modified
|
|
||||||
|
|
||||||
### **1. `converter.ts`**
|
|
||||||
**Added:**
|
|
||||||
- ✅ `blocksToMarkdown()` - Direct blocks → markdown
|
|
||||||
- ✅ `markdownToBlocks()` - Direct markdown → blocks
|
|
||||||
|
|
||||||
**Result:** Clean conversions without HTML pollution
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **2. `index.ts`**
|
|
||||||
**Added:**
|
|
||||||
- ✅ Export `blocksToMarkdown`
|
|
||||||
- ✅ Export `markdownToBlocks`
|
|
||||||
|
|
||||||
**Result:** Functions available throughout the app
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **3. `EditTemplate.tsx`**
|
|
||||||
**Changed:**
|
|
||||||
- ✅ Import new functions
|
|
||||||
- ✅ Use `blocksToMarkdown()` instead of `htmlToMarkdown()`
|
|
||||||
- ✅ Use `markdownToBlocks()` instead of `markdownToHtml() → htmlToBlocks()`
|
|
||||||
- ✅ Direct conversions in all handlers
|
|
||||||
|
|
||||||
**Result:** No more HTML pollution!
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎨 Architecture Summary
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────┐
|
|
||||||
│ USER INTERFACE │
|
|
||||||
├─────────────────────────────────────────┤
|
|
||||||
│ Visual Builder ←→ Markdown │
|
|
||||||
│ │
|
|
||||||
│ Direct conversion (no HTML pollution!) │
|
|
||||||
└─────────────────────────────────────────┘
|
|
||||||
↕ ↕
|
|
||||||
blocksToMarkdown markdownToBlocks
|
|
||||||
↕ ↕
|
|
||||||
┌─────────────────────────────────────────┐
|
|
||||||
│ INTERNAL PIVOT │
|
|
||||||
├─────────────────────────────────────────┤
|
|
||||||
│ HTML (for database & preview only) │
|
|
||||||
│ Generated via blocksToHTML() │
|
|
||||||
└─────────────────────────────────────────┘
|
|
||||||
↕
|
|
||||||
┌─────────────────────────────────────────┐
|
|
||||||
│ DATABASE │
|
|
||||||
└─────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 💡 Key Principles
|
|
||||||
|
|
||||||
### **1. Direct Conversion**
|
|
||||||
- Blocks ↔ Markdown: Direct, no HTML
|
|
||||||
- Only use HTML for database & preview
|
|
||||||
|
|
||||||
### **2. Clean Separation**
|
|
||||||
- **User-facing:** Markdown (clean, readable)
|
|
||||||
- **Internal:** HTML (for compatibility)
|
|
||||||
- **Never mix them!**
|
|
||||||
|
|
||||||
### **3. No Pollution**
|
|
||||||
- Markdown mode shows pure markdown
|
|
||||||
- No `<p>`, no `<br>`, no HTML tags
|
|
||||||
- Clean, mobile-friendly typing
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚀 Benefits
|
|
||||||
|
|
||||||
| Feature | Before | After |
|
|
||||||
|---------|--------|-------|
|
|
||||||
| **Markdown view** | Mixed HTML + markdown ❌ | Pure markdown ✅ |
|
|
||||||
| **HTML pollution** | Accumulates with switches ❌ | Never happens ✅ |
|
|
||||||
| **Mobile typing** | Hard (HTML tags) ❌ | Easy (clean markdown) ✅ |
|
|
||||||
| **Readability** | Poor ❌ | Excellent ✅ |
|
|
||||||
| **Maintainability** | Complex ❌ | Simple ✅ |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📝 Example Output
|
|
||||||
|
|
||||||
### **Before (Polluted):**
|
|
||||||
```
|
|
||||||
[card type="hero"]
|
|
||||||
|
|
||||||
<p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
|
|
||||||
<p>
|
|
||||||
|
|
||||||
# New order received!
|
|
||||||
|
|
||||||
</p>
|
|
||||||
|
|
||||||
</p>
|
|
||||||
|
|
||||||
A customer has placed...
|
|
||||||
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
<br>
|
|
||||||
|
|
||||||
[/card]
|
|
||||||
```
|
|
||||||
|
|
||||||
### **After (Clean):**
|
|
||||||
```
|
|
||||||
[card type="hero"]
|
|
||||||
|
|
||||||
# New order received!
|
|
||||||
|
|
||||||
A customer has placed a new order. Please review and process.
|
|
||||||
|
|
||||||
[/card]
|
|
||||||
```
|
|
||||||
|
|
||||||
**Perfect!** ✅
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎉 Summary
|
|
||||||
|
|
||||||
### **Problem:**
|
|
||||||
- Markdown mode showed HTML with `<p>` and `<br>` tags
|
|
||||||
- Pollution accumulated with mode switches
|
|
||||||
- Not truly "markdown mode"
|
|
||||||
|
|
||||||
### **Solution:**
|
|
||||||
- Created `blocksToMarkdown()` for direct conversion
|
|
||||||
- Created `markdownToBlocks()` for direct parsing
|
|
||||||
- Bypassed HTML entirely for markdown ↔ blocks
|
|
||||||
- HTML only used for database & preview
|
|
||||||
|
|
||||||
### **Result:**
|
|
||||||
- ✅ Clean, pure markdown in markdown mode
|
|
||||||
- ✅ No HTML pollution ever
|
|
||||||
- ✅ Mobile-friendly typing
|
|
||||||
- ✅ Professional, modern approach
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**🎊 FIXED! Test it now with hard refresh (Cmd+Shift+R)! 🚀**
|
|
||||||
|
|
||||||
**Click "Markdown" → See clean markdown, no HTML pollution!**
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
# Converter Fixes Summary
|
|
||||||
|
|
||||||
## Issues Fixed
|
|
||||||
|
|
||||||
### 1. ✅ Exact Event Naming - No Mapping
|
|
||||||
|
|
||||||
**Problem:** API used `order_processing` but Email templates had `order_confirmed`. Required a "bridge" mapping.
|
|
||||||
|
|
||||||
**Solution:** Renamed template methods to match API exactly:
|
|
||||||
- `customer_order_confirmed()` → `customer_order_processing()`
|
|
||||||
- `staff_order_confirmed()` → `staff_order_processing()`
|
|
||||||
- `customer_registered()` → `customer_new_customer()`
|
|
||||||
|
|
||||||
**Result:** Direct 1:1 mapping, no confusion, clean code.
|
|
||||||
|
|
||||||
### 2. ✅ Markdown Converter Respects [card] Boundaries
|
|
||||||
|
|
||||||
**Problem:** `markdownToBlocks()` was splitting by double newlines (`\n\n`), causing:
|
|
||||||
- Raw `[/card]` tags left in output
|
|
||||||
- Each line with double space became a new card
|
|
||||||
- `##` headings not rendered
|
|
||||||
|
|
||||||
**Root Cause:**
|
|
||||||
```typescript
|
|
||||||
// OLD - WRONG
|
|
||||||
const sections = markdown.split(/\n\n+/); // Splits by double newlines!
|
|
||||||
```
|
|
||||||
|
|
||||||
**Solution:** Parse by `[card]...[/card]` boundaries:
|
|
||||||
```typescript
|
|
||||||
// NEW - CORRECT
|
|
||||||
while (remaining.length > 0) {
|
|
||||||
const cardMatch = remaining.match(/^\[card([^\]]*)\]([\s\S]*?)\[\/card\]/);
|
|
||||||
if (cardMatch) {
|
|
||||||
// Extract content between [card] and [/card]
|
|
||||||
const content = cardMatch[2].trim();
|
|
||||||
blocks.push({ type: 'card', content });
|
|
||||||
remaining = remaining.substring(cardMatch[0].length); // Advance!
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Key Changes:**
|
|
||||||
- Uses regex to find `[card]...[/card]` pairs
|
|
||||||
- Extracts content between tags
|
|
||||||
- Advances `remaining` string after each match
|
|
||||||
- No splitting by newlines
|
|
||||||
|
|
||||||
### 3. ⚠️ Markdown Rendering in Preview (Partial)
|
|
||||||
|
|
||||||
**Current State:**
|
|
||||||
- Markdown is stored in database: `## Heading\n\n**bold**`
|
|
||||||
- Frontend CodeEditor shows clean markdown ✅
|
|
||||||
- Preview shows markdown as-is (not converted to HTML) ❌
|
|
||||||
|
|
||||||
**Why:**
|
|
||||||
The preview uses `htmlContent` which contains `[card]## Heading[/card]` but doesn't convert the markdown inside to HTML.
|
|
||||||
|
|
||||||
**Next Steps:**
|
|
||||||
Backend PHP needs to convert markdown to HTML when rendering emails. The `[card]` shortcode handler should:
|
|
||||||
1. Extract content
|
|
||||||
2. Convert markdown to HTML
|
|
||||||
3. Wrap in styled div
|
|
||||||
|
|
||||||
## Files Modified
|
|
||||||
|
|
||||||
1. `/includes/Email/DefaultTemplates.php`
|
|
||||||
- Renamed methods to match API event IDs exactly
|
|
||||||
- Updated subject keys
|
|
||||||
|
|
||||||
2. `/includes/Core/Notifications/TemplateProvider.php`
|
|
||||||
- Removed event mapping
|
|
||||||
- Direct lookup: `$allEmailTemplates[$recipient_type][$event_id]`
|
|
||||||
|
|
||||||
3. `/admin-spa/src/components/EmailBuilder/converter.ts`
|
|
||||||
- Fixed `markdownToBlocks()` to respect `[card]...[/card]` boundaries
|
|
||||||
- Added proper string advancement
|
|
||||||
- No more double-newline splitting
|
|
||||||
|
|
||||||
## Testing Checklist
|
|
||||||
|
|
||||||
- [x] Event names match between API and templates
|
|
||||||
- [x] No mapping/bridging code
|
|
||||||
- [x] Markdown editor shows clean markdown
|
|
||||||
- [x] `[/card]` tags not left in output
|
|
||||||
- [x] Double newlines don't create new cards
|
|
||||||
- [ ] Preview renders markdown as HTML (needs backend fix)
|
|
||||||
- [ ] Headings show as `<h2>` not `##` in preview
|
|
||||||
- [ ] Line breaks work correctly in preview
|
|
||||||
|
|
||||||
## Remaining Work
|
|
||||||
|
|
||||||
**Backend Markdown Rendering:**
|
|
||||||
The WordPress shortcode handler for `[card]` needs to convert markdown content to HTML before rendering.
|
|
||||||
|
|
||||||
Location: Likely in `/includes/Email/` or `/includes/Core/Notifications/`
|
|
||||||
|
|
||||||
Required: A function that processes `[card]` shortcodes and converts their markdown content to HTML using a markdown parser.
|
|
||||||
@@ -1,265 +0,0 @@
|
|||||||
# ✅ Converter Fixed - All Content Now Displays!
|
|
||||||
|
|
||||||
## Problem Solved! 🎉
|
|
||||||
|
|
||||||
The visual builder and code mode now display **ALL content** from templates, not just the last button!
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## The Issue
|
|
||||||
|
|
||||||
**Before:** Only the last button showed in the editor
|
|
||||||
- Visual Builder: Only 1 button visible ❌
|
|
||||||
- Code Mode: Only 1 line of HTML ❌
|
|
||||||
- Preview: Everything rendered correctly ✅
|
|
||||||
|
|
||||||
**Why:** The `htmlToBlocks()` converter was:
|
|
||||||
1. Only looking for `[card]` syntax
|
|
||||||
2. Not recognizing `<div class="card">` HTML (from markdown conversion)
|
|
||||||
3. Skipping all unrecognized content
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## The Solution
|
|
||||||
|
|
||||||
### Updated `converter.ts` ✅
|
|
||||||
|
|
||||||
**What Changed:**
|
|
||||||
1. ✅ Now recognizes **both** `[card]` syntax AND `<div class="card">` HTML
|
|
||||||
2. ✅ Properly extracts all cards regardless of format
|
|
||||||
3. ✅ Preserves all content between cards
|
|
||||||
4. ✅ Handles markdown-converted HTML correctly
|
|
||||||
|
|
||||||
**New Regex:**
|
|
||||||
```typescript
|
|
||||||
// Match both [card] syntax and <div class="card"> HTML
|
|
||||||
const cardRegex = /(?:\[card([^\]]*)\]([\s\S]*?)\[\/card\]|<div class="card(?:\s+card-([^"]+))?"[^>]*>([\s\S]*?)<\/div>)/gs;
|
|
||||||
```
|
|
||||||
|
|
||||||
**New Card Detection:**
|
|
||||||
```typescript
|
|
||||||
// Check both [card] and <div class="card">
|
|
||||||
let cardMatch = part.match(/\[card([^\]]*)\]([\s\S]*?)\[\/card\]/s);
|
|
||||||
|
|
||||||
if (cardMatch) {
|
|
||||||
// [card] syntax
|
|
||||||
content = cardMatch[2].trim();
|
|
||||||
cardType = typeMatch ? typeMatch[1] : 'default';
|
|
||||||
} else {
|
|
||||||
// <div class="card"> HTML syntax
|
|
||||||
const htmlCardMatch = part.match(/<div class="card(?:\s+card-([^"]+))?"[^>]*>([\s\S]*?)<\/div>/s);
|
|
||||||
if (htmlCardMatch) {
|
|
||||||
cardType = htmlCardMatch[1] || 'default';
|
|
||||||
content = htmlCardMatch[2].trim();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## How It Works Now
|
|
||||||
|
|
||||||
### Loading Flow:
|
|
||||||
|
|
||||||
```
|
|
||||||
1. Template loaded (markdown format)
|
|
||||||
↓
|
|
||||||
2. Markdown converted to HTML
|
|
||||||
[card] → <div class="card">
|
|
||||||
↓
|
|
||||||
3. htmlToBlocks() called
|
|
||||||
↓
|
|
||||||
4. Recognizes BOTH formats:
|
|
||||||
- [card]...[/card]
|
|
||||||
- <div class="card">...</div>
|
|
||||||
↓
|
|
||||||
5. Extracts ALL cards
|
|
||||||
↓
|
|
||||||
6. Creates blocks for visual builder
|
|
||||||
↓
|
|
||||||
7. ALL content displays! ✅
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## What's Fixed
|
|
||||||
|
|
||||||
### ✅ Visual Builder:
|
|
||||||
- **Before:** Only 1 button visible
|
|
||||||
- **After:** All cards and buttons visible!
|
|
||||||
|
|
||||||
### ✅ Code Mode:
|
|
||||||
- **Before:** Only 1 line of HTML
|
|
||||||
- **After:** Complete HTML with all cards!
|
|
||||||
|
|
||||||
### ✅ Preview:
|
|
||||||
- **Before:** Already working
|
|
||||||
- **After:** Still working perfectly!
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Files Modified
|
|
||||||
|
|
||||||
### `admin-spa/src/components/EmailBuilder/converter.ts`
|
|
||||||
|
|
||||||
**Changes:**
|
|
||||||
1. Updated `htmlToBlocks()` function
|
|
||||||
2. Added support for `<div class="card">` HTML
|
|
||||||
3. Improved card detection logic
|
|
||||||
4. Fixed TypeScript types
|
|
||||||
|
|
||||||
**Key Improvements:**
|
|
||||||
- Dual format support ([card] and HTML)
|
|
||||||
- Better content extraction
|
|
||||||
- No content loss
|
|
||||||
- Backwards compatible
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Testing Checklist
|
|
||||||
|
|
||||||
### ✅ Visual Builder:
|
|
||||||
- [x] Open any template
|
|
||||||
- [x] All cards visible
|
|
||||||
- [x] All buttons visible
|
|
||||||
- [x] All content preserved
|
|
||||||
- [x] Can edit each block
|
|
||||||
|
|
||||||
### ✅ Code Mode:
|
|
||||||
- [x] Switch to code mode
|
|
||||||
- [x] See complete HTML
|
|
||||||
- [x] All cards present
|
|
||||||
- [x] All buttons present
|
|
||||||
- [x] Can edit HTML
|
|
||||||
|
|
||||||
### ✅ Preview:
|
|
||||||
- [x] Switch to preview
|
|
||||||
- [x] Everything renders
|
|
||||||
- [x] All cards styled
|
|
||||||
- [x] All buttons clickable
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Edge Cases Handled
|
|
||||||
|
|
||||||
### 1. **Mixed Formats**
|
|
||||||
- Template has both `[card]` and `<div class="card">`
|
|
||||||
- ✅ Both recognized and converted
|
|
||||||
|
|
||||||
### 2. **Nested Content**
|
|
||||||
- Cards with complex HTML inside
|
|
||||||
- ✅ Content preserved correctly
|
|
||||||
|
|
||||||
### 3. **Multiple Card Types**
|
|
||||||
- hero, success, info, warning, default
|
|
||||||
- ✅ All types recognized from both formats
|
|
||||||
|
|
||||||
### 4. **Empty Cards**
|
|
||||||
- Cards with no content
|
|
||||||
- ✅ Handled gracefully
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Complete Flow
|
|
||||||
|
|
||||||
### From Database → Editor:
|
|
||||||
|
|
||||||
```
|
|
||||||
Database (Markdown)
|
|
||||||
↓
|
|
||||||
[card type="hero"]
|
|
||||||
New order received!
|
|
||||||
[/card]
|
|
||||||
↓
|
|
||||||
Markdown Detection
|
|
||||||
↓
|
|
||||||
Convert to HTML
|
|
||||||
↓
|
|
||||||
<div class="card card-hero">
|
|
||||||
New order received!
|
|
||||||
</div>
|
|
||||||
↓
|
|
||||||
htmlToBlocks()
|
|
||||||
↓
|
|
||||||
Recognizes <div class="card card-hero">
|
|
||||||
↓
|
|
||||||
Creates Card Block:
|
|
||||||
{
|
|
||||||
type: 'card',
|
|
||||||
cardType: 'hero',
|
|
||||||
content: 'New order received!'
|
|
||||||
}
|
|
||||||
↓
|
|
||||||
Visual Builder Displays Card ✅
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
| Component | Before | After |
|
|
||||||
|-----------|--------|-------|
|
|
||||||
| Visual Builder | 1 button only | All content ✅ |
|
|
||||||
| Code Mode | 1 line | Complete HTML ✅ |
|
|
||||||
| Preview | Working | Still working ✅ |
|
|
||||||
| Card Detection | [card] only | Both formats ✅ |
|
|
||||||
| Content Loss | Yes ❌ | None ✅ |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## What Users See Now
|
|
||||||
|
|
||||||
### Visual Builder:
|
|
||||||
- ✅ Hero card with gradient
|
|
||||||
- ✅ Order details card
|
|
||||||
- ✅ Customer contact card
|
|
||||||
- ✅ Items ordered card
|
|
||||||
- ✅ Process order button
|
|
||||||
- ✅ Everything editable!
|
|
||||||
|
|
||||||
### Code Mode:
|
|
||||||
- ✅ Complete HTML structure
|
|
||||||
- ✅ All cards with proper classes
|
|
||||||
- ✅ All buttons with proper styling
|
|
||||||
- ✅ Can edit any part
|
|
||||||
|
|
||||||
### Preview:
|
|
||||||
- ✅ Beautiful rendering
|
|
||||||
- ✅ Brand colors applied
|
|
||||||
- ✅ All content visible
|
|
||||||
- ✅ Professional appearance
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Performance
|
|
||||||
|
|
||||||
**Impact:** None
|
|
||||||
- Same parsing speed
|
|
||||||
- No extra overhead
|
|
||||||
- Efficient regex matching
|
|
||||||
- No performance degradation
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Backwards Compatibility
|
|
||||||
|
|
||||||
**100% Compatible:**
|
|
||||||
- Old [card] syntax still works
|
|
||||||
- New HTML format works
|
|
||||||
- Mixed formats work
|
|
||||||
- No breaking changes
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Next Steps
|
|
||||||
|
|
||||||
**Nothing!** The system is complete! 🎉
|
|
||||||
|
|
||||||
**Test it now:**
|
|
||||||
1. Hard refresh browser (Cmd+Shift+R)
|
|
||||||
2. Open any template
|
|
||||||
3. ✅ See all content in visual builder
|
|
||||||
4. ✅ See all content in code mode
|
|
||||||
5. ✅ See all content in preview
|
|
||||||
|
|
||||||
**Everything works! 🚀**
|
|
||||||
@@ -1,488 +0,0 @@
|
|||||||
# 🎨 Custom Email System - Implementation Complete!
|
|
||||||
|
|
||||||
**Date:** November 12, 2025
|
|
||||||
**Status:** ✅ **CORE COMPLETE - READY FOR TESTING**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📊 What Was Built
|
|
||||||
|
|
||||||
### 1. Email Manager (`EmailManager.php`) ✅
|
|
||||||
|
|
||||||
**Purpose:** Manages email sending and disables WooCommerce emails
|
|
||||||
|
|
||||||
**Features:**
|
|
||||||
- ✅ Disables all WooCommerce default emails (prevents duplicates)
|
|
||||||
- ✅ Hooks into ALL WooCommerce order status changes
|
|
||||||
- ✅ Hooks into customer, product, stock events
|
|
||||||
- ✅ Checks if events are enabled before sending
|
|
||||||
- ✅ Sends via `wp_mail()` (SMTP plugin compatible!)
|
|
||||||
- ✅ Singleton pattern for single instance
|
|
||||||
|
|
||||||
**WooCommerce Hooks:**
|
|
||||||
```php
|
|
||||||
// Order status changes
|
|
||||||
- woocommerce_order_status_pending_to_processing
|
|
||||||
- woocommerce_order_status_completed
|
|
||||||
- woocommerce_order_status_cancelled
|
|
||||||
- woocommerce_order_status_refunded
|
|
||||||
- woocommerce_new_order (admin notification)
|
|
||||||
|
|
||||||
// Customer events
|
|
||||||
- woocommerce_new_customer_note
|
|
||||||
- woocommerce_created_customer
|
|
||||||
|
|
||||||
// Product events
|
|
||||||
- woocommerce_low_stock
|
|
||||||
- woocommerce_no_stock
|
|
||||||
- woocommerce_product_set_stock
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2. Email Renderer (`EmailRenderer.php`) ✅
|
|
||||||
|
|
||||||
**Purpose:** Renders beautiful HTML emails from templates
|
|
||||||
|
|
||||||
**Features:**
|
|
||||||
- ✅ Loads design templates (modern, classic, minimal)
|
|
||||||
- ✅ Replaces variables in subject and body
|
|
||||||
- ✅ Gets recipient email (staff/customer)
|
|
||||||
- ✅ Extracts order/product/customer data
|
|
||||||
- ✅ Renders final HTML email
|
|
||||||
- ✅ Filter hook: `apply_filters('woonoow_email_template', $path, $design)`
|
|
||||||
|
|
||||||
**Variable System:**
|
|
||||||
```php
|
|
||||||
Order Variables:
|
|
||||||
- {order_number}, {order_total}, {order_date}
|
|
||||||
- {customer_name}, {customer_email}
|
|
||||||
- {billing_address}, {shipping_address}
|
|
||||||
- {payment_method}, {shipping_method}
|
|
||||||
- {order_items} (HTML table)
|
|
||||||
|
|
||||||
Product Variables:
|
|
||||||
- {product_name}, {product_sku}, {product_price}
|
|
||||||
- {stock_quantity}, {stock_status}
|
|
||||||
|
|
||||||
Customer Variables:
|
|
||||||
- {customer_name}, {customer_email}
|
|
||||||
- {customer_username}
|
|
||||||
|
|
||||||
Store Variables:
|
|
||||||
- {store_name}, {store_url}
|
|
||||||
- {current_year}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3. Email Design Templates (3 HTML Files) ✅
|
|
||||||
|
|
||||||
#### **Modern Template** (`modern.html`)
|
|
||||||
- ✅ Clean, minimalist, Apple-inspired design
|
|
||||||
- ✅ Sans-serif fonts (system fonts)
|
|
||||||
- ✅ Subtle shadows and rounded corners
|
|
||||||
- ✅ Dark mode support
|
|
||||||
- ✅ Mobile responsive
|
|
||||||
- ✅ 2024 design trends
|
|
||||||
|
|
||||||
**Colors:**
|
|
||||||
- Background: `#f5f5f7`
|
|
||||||
- Text: `#1d1d1f`
|
|
||||||
- Accent: `#0071e3` (Apple blue)
|
|
||||||
- Muted: `#6e6e73`
|
|
||||||
|
|
||||||
#### **Classic Template** (`classic.html`)
|
|
||||||
- ✅ Professional, traditional design
|
|
||||||
- ✅ Serif fonts (Georgia)
|
|
||||||
- ✅ Gradient header (purple gradient)
|
|
||||||
- ✅ Table styling with alternating rows
|
|
||||||
- ✅ Business-appropriate
|
|
||||||
- ✅ Bold, confident look
|
|
||||||
|
|
||||||
**Colors:**
|
|
||||||
- Gradient: `#667eea` to `#764ba2`
|
|
||||||
- Background: `#f4f4f4`
|
|
||||||
- Text: `#333333`
|
|
||||||
|
|
||||||
#### **Minimal Template** (`minimal.html`)
|
|
||||||
- ✅ Ultra-clean, brutalist design
|
|
||||||
- ✅ Monospace font (Courier New)
|
|
||||||
- ✅ Black & white only
|
|
||||||
- ✅ Text-focused, no distractions
|
|
||||||
- ✅ Dark mode (inverted colors)
|
|
||||||
- ✅ High contrast
|
|
||||||
|
|
||||||
**Colors:**
|
|
||||||
- Black: `#000000`
|
|
||||||
- White: `#ffffff`
|
|
||||||
- That's it!
|
|
||||||
|
|
||||||
**All Templates Include:**
|
|
||||||
- ✅ Email client compatibility (Outlook, Gmail, Apple Mail)
|
|
||||||
- ✅ Mobile responsive design
|
|
||||||
- ✅ Dark mode support
|
|
||||||
- ✅ Proper HTML email structure
|
|
||||||
- ✅ Inline CSS for maximum compatibility
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 4. Rich Text Editor (`RichTextEditor.tsx`) ✅
|
|
||||||
|
|
||||||
**Purpose:** Modern WYSIWYG editor for email content
|
|
||||||
|
|
||||||
**Technology:** TipTap (React)
|
|
||||||
|
|
||||||
**Features:**
|
|
||||||
- ✅ Bold, Italic formatting
|
|
||||||
- ✅ Bullet lists, numbered lists
|
|
||||||
- ✅ Link insertion
|
|
||||||
- ✅ Undo/Redo
|
|
||||||
- ✅ Variable insertion buttons
|
|
||||||
- ✅ Placeholder text
|
|
||||||
- ✅ Clean, minimal toolbar
|
|
||||||
- ✅ HTML output
|
|
||||||
|
|
||||||
**UI:**
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────┐
|
|
||||||
│ [B] [I] │ [•] [1.] │ [🔗] │ [↶] [↷] │ ← Toolbar
|
|
||||||
├─────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ [Rich text content here...] │
|
|
||||||
│ │
|
|
||||||
├─────────────────────────────────────┤
|
|
||||||
│ Variables: [{order_number}] [...] │ ← Quick insert
|
|
||||||
└─────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 5. Template Editor Updated ✅
|
|
||||||
|
|
||||||
**Changes:**
|
|
||||||
- ✅ Replaced `<Textarea>` with `<RichTextEditor>`
|
|
||||||
- ✅ Variables shown as clickable buttons
|
|
||||||
- ✅ Better UX for content editing
|
|
||||||
- ✅ HTML output for beautiful emails
|
|
||||||
- ✅ Live variable insertion
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🏗️ Architecture
|
|
||||||
|
|
||||||
```
|
|
||||||
WooCommerce Event
|
|
||||||
↓
|
|
||||||
EmailManager (checks if enabled)
|
|
||||||
↓
|
|
||||||
EmailRenderer
|
|
||||||
↓
|
|
||||||
┌──────────────────────┐
|
|
||||||
│ 1. Get template │ → TemplateProvider
|
|
||||||
│ 2. Get variables │ → Order/Product/Customer data
|
|
||||||
│ 3. Replace variables │ → {order_number} → #12345
|
|
||||||
│ 4. Load design │ → modern.html / classic.html / minimal.html
|
|
||||||
│ 5. Render HTML │ → {{email_content}} → Final HTML
|
|
||||||
└──────────────────────┘
|
|
||||||
↓
|
|
||||||
wp_mail() → SMTP Plugin → Customer's Inbox
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 How It Works
|
|
||||||
|
|
||||||
### Example: Order Completed Email
|
|
||||||
|
|
||||||
1. **WooCommerce fires hook:**
|
|
||||||
```php
|
|
||||||
do_action('woocommerce_order_status_completed', $order_id, $order);
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **EmailManager catches it:**
|
|
||||||
```php
|
|
||||||
public function send_order_completed_email($order_id, $order) {
|
|
||||||
if (!$this->is_event_enabled('order_completed', 'email', 'customer')) {
|
|
||||||
return; // Event disabled, skip
|
|
||||||
}
|
|
||||||
$this->send_email('order_completed', 'customer', $order);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **EmailRenderer renders:**
|
|
||||||
```php
|
|
||||||
$template = TemplateProvider::get_template('order_completed', 'email');
|
|
||||||
$variables = $this->get_variables('order_completed', $order);
|
|
||||||
$content = $this->replace_variables($template['body'], $variables);
|
|
||||||
$html = $this->render_html('modern.html', $content, $subject, $variables);
|
|
||||||
```
|
|
||||||
|
|
||||||
4. **Email sent:**
|
|
||||||
```php
|
|
||||||
wp_mail($customer_email, $subject, $html, $headers);
|
|
||||||
```
|
|
||||||
|
|
||||||
5. **Customer receives beautiful HTML email!** 🎉
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📁 File Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
woonoow/
|
|
||||||
├── includes/
|
|
||||||
│ └── Core/
|
|
||||||
│ └── Notifications/
|
|
||||||
│ ├── EmailManager.php ← Hooks & sending
|
|
||||||
│ ├── EmailRenderer.php ← Template rendering
|
|
||||||
│ └── TemplateProvider.php ← Content templates
|
|
||||||
├── templates/
|
|
||||||
│ └── emails/
|
|
||||||
│ ├── modern.html ← Design template 1
|
|
||||||
│ ├── classic.html ← Design template 2
|
|
||||||
│ └── minimal.html ← Design template 3
|
|
||||||
└── admin-spa/
|
|
||||||
└── src/
|
|
||||||
├── components/
|
|
||||||
│ └── ui/
|
|
||||||
│ └── rich-text-editor.tsx ← TipTap editor
|
|
||||||
└── routes/
|
|
||||||
└── Settings/
|
|
||||||
└── Notifications/
|
|
||||||
└── TemplateEditor.tsx ← Updated UI
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✅ What's Complete
|
|
||||||
|
|
||||||
- [x] EmailManager with WooCommerce hooks
|
|
||||||
- [x] EmailRenderer with variable system
|
|
||||||
- [x] 3 beautiful HTML email templates
|
|
||||||
- [x] Rich text editor (TipTap)
|
|
||||||
- [x] Template editor UI updated
|
|
||||||
- [x] WooCommerce email disabling
|
|
||||||
- [x] Filter hooks for extensibility
|
|
||||||
- [x] SMTP plugin compatibility
|
|
||||||
- [x] Dark mode support
|
|
||||||
- [x] Mobile responsive
|
|
||||||
- [x] Bootstrap integration
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚧 What's Pending
|
|
||||||
|
|
||||||
### 1. Design Template Selector (UI)
|
|
||||||
Add a dropdown in Notifications settings to choose:
|
|
||||||
- Modern (default)
|
|
||||||
- Classic
|
|
||||||
- Minimal
|
|
||||||
|
|
||||||
**Location:** Settings → Notifications → Channels tab
|
|
||||||
|
|
||||||
**Implementation:**
|
|
||||||
```tsx
|
|
||||||
<Select
|
|
||||||
value={designTemplate}
|
|
||||||
onValueChange={setDesignTemplate}
|
|
||||||
>
|
|
||||||
<SelectItem value="modern">Modern (Clean & Minimal)</SelectItem>
|
|
||||||
<SelectItem value="classic">Classic (Professional)</SelectItem>
|
|
||||||
<SelectItem value="minimal">Minimal (Black & White)</SelectItem>
|
|
||||||
</Select>
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Content Templates
|
|
||||||
Update `TemplateProvider::get_default_templates()` with better default content for each event.
|
|
||||||
|
|
||||||
**Current:** Generic text
|
|
||||||
**Needed:** Contextual, professional content
|
|
||||||
|
|
||||||
### 3. Testing
|
|
||||||
- [ ] Test order processing email
|
|
||||||
- [ ] Test order completed email
|
|
||||||
- [ ] Test order refunded email
|
|
||||||
- [ ] Test new customer email
|
|
||||||
- [ ] Test low stock email
|
|
||||||
- [ ] Test all 3 design templates
|
|
||||||
- [ ] Test variable replacement
|
|
||||||
- [ ] Test SMTP delivery
|
|
||||||
- [ ] Test mobile rendering
|
|
||||||
- [ ] Test dark mode
|
|
||||||
|
|
||||||
### 4. Template Preview
|
|
||||||
Add live preview in TemplateEditor:
|
|
||||||
- Show how email will look
|
|
||||||
- Preview with sample data
|
|
||||||
- Switch between design templates
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎨 Design Template Comparison
|
|
||||||
|
|
||||||
| Feature | Modern | Classic | Minimal |
|
|
||||||
|---------|--------|---------|---------|
|
|
||||||
| **Font** | Sans-serif | Serif | Monospace |
|
|
||||||
| **Style** | Clean, Apple-like | Professional | Brutalist |
|
|
||||||
| **Colors** | Blue accent | Purple gradient | Black & white |
|
|
||||||
| **Best For** | Tech, SaaS | Business, Corporate | Art, Design |
|
|
||||||
| **Dark Mode** | ✅ Adaptive | ❌ No | ✅ Inverted |
|
|
||||||
| **Complexity** | Medium | High | Low |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔧 Configuration
|
|
||||||
|
|
||||||
### Enable/Disable Custom Emails
|
|
||||||
|
|
||||||
```php
|
|
||||||
// In notification settings
|
|
||||||
$settings['use_custom_emails'] = true; // Default: true
|
|
||||||
|
|
||||||
// To keep WooCommerce emails:
|
|
||||||
$settings['use_custom_emails'] = false;
|
|
||||||
```
|
|
||||||
|
|
||||||
### Choose Design Template
|
|
||||||
|
|
||||||
```php
|
|
||||||
// In notification settings
|
|
||||||
$settings['email_design_template'] = 'modern'; // modern, classic, minimal
|
|
||||||
```
|
|
||||||
|
|
||||||
### Filter Template Path
|
|
||||||
|
|
||||||
```php
|
|
||||||
add_filter('woonoow_email_template', function($path, $design) {
|
|
||||||
// Use custom template
|
|
||||||
return '/path/to/custom-template.html';
|
|
||||||
}, 10, 2);
|
|
||||||
```
|
|
||||||
|
|
||||||
### Filter Variables
|
|
||||||
|
|
||||||
```php
|
|
||||||
add_filter('woonoow_email_variables', function($variables, $event_id, $data) {
|
|
||||||
// Add custom variable
|
|
||||||
$variables['custom_field'] = 'Custom Value';
|
|
||||||
return $variables;
|
|
||||||
}, 10, 3);
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📊 Impact
|
|
||||||
|
|
||||||
### Before (WooCommerce Emails)
|
|
||||||
- ❌ Outdated design
|
|
||||||
- ❌ Hard to customize
|
|
||||||
- ❌ Inconsistent with brand
|
|
||||||
- ❌ Fragmented management
|
|
||||||
- ❌ No modern features
|
|
||||||
|
|
||||||
### After (WooNooW Emails)
|
|
||||||
- ✅ Modern, beautiful design
|
|
||||||
- ✅ Easy customization (rich text editor)
|
|
||||||
- ✅ Consistent branding
|
|
||||||
- ✅ Unified management
|
|
||||||
- ✅ Dark mode, mobile responsive
|
|
||||||
- ✅ 3 design choices
|
|
||||||
- ✅ Professional templates
|
|
||||||
- ✅ Better customer experience
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚀 Next Steps
|
|
||||||
|
|
||||||
1. **Add Design Template Selector**
|
|
||||||
- UI in Notifications settings
|
|
||||||
- Save preference to database
|
|
||||||
- Preview each template
|
|
||||||
|
|
||||||
2. **Improve Content Templates**
|
|
||||||
- Better default text
|
|
||||||
- More professional tone
|
|
||||||
- Context-aware content
|
|
||||||
|
|
||||||
3. **Test Everything**
|
|
||||||
- Place test orders
|
|
||||||
- Trigger all events
|
|
||||||
- Check email delivery
|
|
||||||
- Verify rendering
|
|
||||||
|
|
||||||
4. **Add Template Preview**
|
|
||||||
- Live preview in editor
|
|
||||||
- Sample data
|
|
||||||
- Design template switcher
|
|
||||||
|
|
||||||
5. **Documentation**
|
|
||||||
- User guide
|
|
||||||
- Developer docs
|
|
||||||
- Video tutorials
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 💡 Future Enhancements
|
|
||||||
|
|
||||||
### Phase 2 (Optional)
|
|
||||||
- [ ] Email analytics (open rates, clicks)
|
|
||||||
- [ ] A/B testing
|
|
||||||
- [ ] Premium template packs
|
|
||||||
- [ ] Custom template builder
|
|
||||||
- [ ] Email scheduling
|
|
||||||
- [ ] Conditional content
|
|
||||||
- [ ] Multi-language support
|
|
||||||
- [ ] Email attachments
|
|
||||||
|
|
||||||
### Phase 3 (Advanced)
|
|
||||||
- [ ] Drag & drop email builder
|
|
||||||
- [ ] Template marketplace
|
|
||||||
- [ ] Email automation workflows
|
|
||||||
- [ ] Segmentation
|
|
||||||
- [ ] Personalization engine
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎉 Success Metrics
|
|
||||||
|
|
||||||
- ✅ **Zero WooCommerce email conflicts**
|
|
||||||
- ✅ **Beautiful, modern email design**
|
|
||||||
- ✅ **Easy content editing (rich text)**
|
|
||||||
- ✅ **3 design templates**
|
|
||||||
- ✅ **SMTP plugin compatible**
|
|
||||||
- ✅ **Dark mode support**
|
|
||||||
- ✅ **Mobile responsive**
|
|
||||||
- ✅ **Extensible with filters**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📞 Technical Notes
|
|
||||||
|
|
||||||
### Email Client Compatibility
|
|
||||||
- ✅ Gmail (web, mobile)
|
|
||||||
- ✅ Apple Mail (macOS, iOS)
|
|
||||||
- ✅ Outlook (desktop, web)
|
|
||||||
- ✅ Yahoo Mail
|
|
||||||
- ✅ ProtonMail
|
|
||||||
- ✅ Thunderbird
|
|
||||||
|
|
||||||
### CSS Support
|
|
||||||
- ✅ Inline CSS (maximum compatibility)
|
|
||||||
- ✅ Media queries (responsive)
|
|
||||||
- ✅ Dark mode queries
|
|
||||||
- ✅ Table-based layout (Outlook)
|
|
||||||
|
|
||||||
### Security
|
|
||||||
- ✅ Escapes all variables
|
|
||||||
- ✅ Sanitizes HTML output
|
|
||||||
- ✅ No external resources
|
|
||||||
- ✅ No tracking pixels (optional)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Status:** 🎉 **CORE SYSTEM COMPLETE!**
|
|
||||||
**Ready for:** Testing & UI polish
|
|
||||||
**Estimated time to production:** 1-2 days
|
|
||||||
|
|
||||||
**You now have a modern, beautiful, extensible email system that rivals Shopify and BigCommerce!** 🚀
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
# Event-Template Mismatch Analysis
|
|
||||||
|
|
||||||
## Current State
|
|
||||||
|
|
||||||
### Events API (`NotificationsController.php`)
|
|
||||||
Defines 9 events total:
|
|
||||||
|
|
||||||
**Staff (4 events):**
|
|
||||||
1. `order_placed` - When order is placed
|
|
||||||
2. `order_cancelled` - When order is cancelled
|
|
||||||
3. `low_stock` - Product stock low
|
|
||||||
4. `out_of_stock` - Product out of stock
|
|
||||||
|
|
||||||
**Customer (5 events):**
|
|
||||||
1. `order_processing` - Order being processed
|
|
||||||
2. `order_completed` - Order completed
|
|
||||||
3. `order_refunded` - Order refunded
|
|
||||||
4. `new_customer` - Customer registers
|
|
||||||
5. `customer_note` - Note added to order
|
|
||||||
|
|
||||||
### DefaultTemplates.php
|
|
||||||
Has 15 templates total:
|
|
||||||
|
|
||||||
**Staff (7 templates):**
|
|
||||||
1. `order_placed` ✅
|
|
||||||
2. `order_processing` ❌ (no event)
|
|
||||||
3. `order_shipped` ❌ (no event)
|
|
||||||
4. `order_completed` ❌ (no event)
|
|
||||||
5. `order_cancelled` ✅
|
|
||||||
6. `payment_received` ❌ (no event)
|
|
||||||
7. `payment_failed` ❌ (no event)
|
|
||||||
|
|
||||||
**Customer (8 templates):**
|
|
||||||
1. `order_placed` ❌ (no event)
|
|
||||||
2. `order_processing` ✅
|
|
||||||
3. `order_shipped` ❌ (no event)
|
|
||||||
4. `order_completed` ✅
|
|
||||||
5. `order_cancelled` ❌ (no event)
|
|
||||||
6. `payment_received` ❌ (no event)
|
|
||||||
7. `payment_failed` ❌ (no event)
|
|
||||||
8. `new_customer` ✅
|
|
||||||
|
|
||||||
**Missing from templates:**
|
|
||||||
- `order_refunded` (customer)
|
|
||||||
- `customer_note` (customer)
|
|
||||||
- `low_stock` (staff)
|
|
||||||
- `out_of_stock` (staff)
|
|
||||||
|
|
||||||
## The Problem
|
|
||||||
|
|
||||||
**Templates exist without events** - These templates will never be used because no event triggers them.
|
|
||||||
|
|
||||||
**Events exist without templates** - These events will use fallback templates.
|
|
||||||
|
|
||||||
## Recommended Solution
|
|
||||||
|
|
||||||
**Events API should be the source of truth.** Add missing events to match a complete e-commerce notification system:
|
|
||||||
|
|
||||||
### Proposed Complete Event List
|
|
||||||
|
|
||||||
**Staff Events (7):**
|
|
||||||
1. `order_placed` - New order notification
|
|
||||||
2. `order_processing` - Order confirmed, ready to process
|
|
||||||
3. `order_cancelled` - Order cancelled
|
|
||||||
4. `low_stock` - Product stock low
|
|
||||||
5. `out_of_stock` - Product out of stock
|
|
||||||
6. `payment_received` - Payment confirmed
|
|
||||||
7. `payment_failed` - Payment failed
|
|
||||||
|
|
||||||
**Customer Events (8):**
|
|
||||||
1. `order_processing` - Order being processed
|
|
||||||
2. `order_shipped` - Order shipped with tracking
|
|
||||||
3. `order_completed` - Order delivered
|
|
||||||
4. `order_cancelled` - Order cancelled
|
|
||||||
5. `order_refunded` - Order refunded
|
|
||||||
6. `payment_received` - Payment confirmed
|
|
||||||
7. `payment_failed` - Payment failed, retry
|
|
||||||
8. `new_customer` - Welcome email
|
|
||||||
9. `customer_note` - Note added to order
|
|
||||||
|
|
||||||
**Total: 16 events** (7 staff + 9 customer)
|
|
||||||
|
|
||||||
## Action Items
|
|
||||||
|
|
||||||
1. **Add missing events to NotificationsController.php:**
|
|
||||||
- Staff: `order_processing`, `order_shipped`, `order_completed`, `payment_received`, `payment_failed`
|
|
||||||
- Customer: `order_placed`, `order_shipped`, `order_cancelled`, `payment_received`, `payment_failed`
|
|
||||||
|
|
||||||
2. **Add missing templates to DefaultTemplates.php:**
|
|
||||||
- Customer: `order_refunded`, `customer_note`
|
|
||||||
- Staff: `low_stock`, `out_of_stock`
|
|
||||||
|
|
||||||
3. **Update TemplateProvider.php** to handle all events
|
|
||||||
|
|
||||||
## Why Events API is Source of Truth
|
|
||||||
|
|
||||||
- Events define **what actually happens** in the system
|
|
||||||
- Templates are just **content** for those events
|
|
||||||
- If an event doesn't exist, the template is useless
|
|
||||||
- If a template doesn't exist, we can create a fallback
|
|
||||||
|
|
||||||
**Conclusion:** Expand Events API to include all meaningful e-commerce notifications, then ensure templates exist for each.
|
|
||||||
@@ -1,377 +0,0 @@
|
|||||||
# ✅ HTML as Single Source of Truth - IMPLEMENTED! 🚀
|
|
||||||
|
|
||||||
## Problem Solved! 🎉
|
|
||||||
|
|
||||||
**Before:** Confusing data flow with markdown/HTML/blocks competing
|
|
||||||
**After:** Clean architecture with HTML as the single source of truth
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## The Architecture
|
|
||||||
|
|
||||||
### **HTML = Source of Truth**
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────┐
|
|
||||||
│ DATABASE (HTML) │
|
|
||||||
│ Single source of truth for all content │
|
|
||||||
└─────────────────────────────────────────┘
|
|
||||||
↓
|
|
||||||
┌─────────────────────────────────────────┐
|
|
||||||
│ EDITOR STATE (htmlContent) │
|
|
||||||
│ Always contains the current HTML │
|
|
||||||
└─────────────────────────────────────────┘
|
|
||||||
↓
|
|
||||||
┌───────────┴───────────┐
|
|
||||||
↓ ↓
|
|
||||||
┌──────────────┐ ┌──────────────┐
|
|
||||||
│ Code Mode │ │ Visual Mode │
|
|
||||||
│ (HTML view) │ │ (Blocks view)│
|
|
||||||
└──────────────┘ └──────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## How It Works
|
|
||||||
|
|
||||||
### 1. **Loading Template**
|
|
||||||
```typescript
|
|
||||||
// Load from database
|
|
||||||
const template = await fetchTemplate();
|
|
||||||
|
|
||||||
// One-time conversion: Markdown → HTML (if needed)
|
|
||||||
let html = template.body;
|
|
||||||
if (isMarkdown(html)) {
|
|
||||||
html = markdownToHtml(html);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set HTML as source of truth
|
|
||||||
setHtmlContent(html);
|
|
||||||
setBlocks(htmlToBlocks(html)); // Visual view
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. **Editing in Visual Mode**
|
|
||||||
```typescript
|
|
||||||
// User edits blocks
|
|
||||||
handleBlocksChange(newBlocks) {
|
|
||||||
setBlocks(newBlocks); // Update visual view
|
|
||||||
setHtmlContent(blocksToHTML(newBlocks)); // Sync to HTML
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTML is always up-to-date!
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. **Editing in Code Mode**
|
|
||||||
```typescript
|
|
||||||
// User edits HTML directly
|
|
||||||
handleHtmlChange(newHtml) {
|
|
||||||
setHtmlContent(newHtml); // Update HTML directly
|
|
||||||
}
|
|
||||||
|
|
||||||
// HTML is the source, no conversion needed!
|
|
||||||
```
|
|
||||||
|
|
||||||
### 4. **Switching Modes**
|
|
||||||
```typescript
|
|
||||||
// Switching TO code mode
|
|
||||||
if (!codeMode) {
|
|
||||||
const currentHtml = blocksToHTML(blocks);
|
|
||||||
setHtmlContent(currentHtml); // Update HTML from blocks
|
|
||||||
}
|
|
||||||
|
|
||||||
// Switching FROM code mode
|
|
||||||
else {
|
|
||||||
setBlocks(htmlToBlocks(htmlContent)); // Update blocks from HTML
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mode switching = Format conversion for display only
|
|
||||||
// HTML remains the source of truth
|
|
||||||
```
|
|
||||||
|
|
||||||
### 5. **Saving**
|
|
||||||
```typescript
|
|
||||||
// Always save HTML (source of truth)
|
|
||||||
await saveTemplate({
|
|
||||||
subject,
|
|
||||||
body: htmlContent, // Just save it!
|
|
||||||
});
|
|
||||||
|
|
||||||
// No conversion needed, no confusion!
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Data Flow
|
|
||||||
|
|
||||||
### Visual Mode → Code Mode:
|
|
||||||
```
|
|
||||||
User edits blocks
|
|
||||||
↓
|
|
||||||
Blocks updated
|
|
||||||
↓
|
|
||||||
HTML updated (blocksToHTML)
|
|
||||||
↓
|
|
||||||
User switches to code mode
|
|
||||||
↓
|
|
||||||
Show HTML in editor
|
|
||||||
↓
|
|
||||||
✅ All changes preserved!
|
|
||||||
```
|
|
||||||
|
|
||||||
### Code Mode → Visual Mode:
|
|
||||||
```
|
|
||||||
User edits HTML
|
|
||||||
↓
|
|
||||||
HTML updated directly
|
|
||||||
↓
|
|
||||||
User switches to visual mode
|
|
||||||
↓
|
|
||||||
Convert HTML → Blocks
|
|
||||||
↓
|
|
||||||
✅ All changes preserved!
|
|
||||||
```
|
|
||||||
|
|
||||||
### Visual Mode → Save:
|
|
||||||
```
|
|
||||||
User edits blocks
|
|
||||||
↓
|
|
||||||
HTML updated continuously
|
|
||||||
↓
|
|
||||||
User clicks save
|
|
||||||
↓
|
|
||||||
Save HTML to database
|
|
||||||
↓
|
|
||||||
✅ Perfect sync!
|
|
||||||
```
|
|
||||||
|
|
||||||
### Code Mode → Save:
|
|
||||||
```
|
|
||||||
User edits HTML
|
|
||||||
↓
|
|
||||||
HTML updated directly
|
|
||||||
↓
|
|
||||||
User clicks save
|
|
||||||
↓
|
|
||||||
Save HTML to database
|
|
||||||
↓
|
|
||||||
✅ Perfect sync!
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## What Changed
|
|
||||||
|
|
||||||
### Before (Confusing):
|
|
||||||
```typescript
|
|
||||||
// Multiple sources of truth
|
|
||||||
const [body, setBody] = useState(''); // HTML?
|
|
||||||
const [blocks, setBlocks] = useState([]); // Blocks?
|
|
||||||
const [markdown, setMarkdown] = useState(''); // Markdown?
|
|
||||||
|
|
||||||
// Confusing save logic
|
|
||||||
const htmlBody = codeMode ? body : blocksToHTML(blocks);
|
|
||||||
|
|
||||||
// Markdown detection on every load
|
|
||||||
if (isMarkdown(template.body)) {
|
|
||||||
// Convert...
|
|
||||||
}
|
|
||||||
|
|
||||||
// Lost changes when switching modes!
|
|
||||||
```
|
|
||||||
|
|
||||||
### After (Clean):
|
|
||||||
```typescript
|
|
||||||
// Single source of truth
|
|
||||||
const [htmlContent, setHtmlContent] = useState(''); // HTML!
|
|
||||||
const [blocks, setBlocks] = useState([]); // Visual view only
|
|
||||||
|
|
||||||
// Clean save logic
|
|
||||||
await saveTemplate({ body: htmlContent });
|
|
||||||
|
|
||||||
// One-time markdown conversion
|
|
||||||
if (isMarkdown(template.body)) {
|
|
||||||
html = markdownToHtml(template.body);
|
|
||||||
// After this, always HTML
|
|
||||||
}
|
|
||||||
|
|
||||||
// Changes always preserved!
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Benefits
|
|
||||||
|
|
||||||
### ✅ No Data Loss:
|
|
||||||
- All changes preserved when switching modes
|
|
||||||
- HTML always in sync
|
|
||||||
- No confusion about which format is "current"
|
|
||||||
|
|
||||||
### ✅ Clear Priority:
|
|
||||||
- **HTML** = Source of truth (always)
|
|
||||||
- **Markdown** = Input format only (one-time conversion)
|
|
||||||
- **Blocks** = Visual representation (view only)
|
|
||||||
|
|
||||||
### ✅ Simple Logic:
|
|
||||||
- Save = Just save HTML
|
|
||||||
- Load = Just load HTML
|
|
||||||
- Switch modes = Convert for display only
|
|
||||||
|
|
||||||
### ✅ User Friendly:
|
|
||||||
- Edit in any mode
|
|
||||||
- Switch freely
|
|
||||||
- Never lose work
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Mode Comparison
|
|
||||||
|
|
||||||
| Mode | What User Sees | What Happens | HTML Updated? |
|
|
||||||
|------|----------------|--------------|---------------|
|
|
||||||
| **Visual** | Blocks/Cards | Edit blocks → HTML synced | ✅ Yes (continuous) |
|
|
||||||
| **Code** | HTML code | Edit HTML directly | ✅ Yes (direct) |
|
|
||||||
| **Preview** | Rendered email | View only | ❌ No |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Markdown Handling
|
|
||||||
|
|
||||||
### One-Time Conversion:
|
|
||||||
```typescript
|
|
||||||
// On template load
|
|
||||||
if (detectContentType(template.body) === 'markdown') {
|
|
||||||
html = markdownToHtml(template.body);
|
|
||||||
setHtmlContent(html);
|
|
||||||
}
|
|
||||||
|
|
||||||
// After this, HTML is always used
|
|
||||||
// No more markdown detection!
|
|
||||||
```
|
|
||||||
|
|
||||||
### Why This Works:
|
|
||||||
- ✅ Default templates can be markdown (easier to write)
|
|
||||||
- ✅ Converted to HTML on first load
|
|
||||||
- ✅ After that, always HTML in database
|
|
||||||
- ✅ Users never see markdown (only HTML or visual)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Files Modified
|
|
||||||
|
|
||||||
### `EditTemplate.tsx`
|
|
||||||
**Changes:**
|
|
||||||
1. ✅ Renamed `body` → `htmlContent` (clarity)
|
|
||||||
2. ✅ Made `htmlContent` the single source of truth
|
|
||||||
3. ✅ Updated `handleBlocksChange` to sync HTML
|
|
||||||
4. ✅ Added `handleHtmlChange` for code mode
|
|
||||||
5. ✅ Fixed `handleCodeModeToggle` to convert properly
|
|
||||||
6. ✅ Updated `handleSave` to always save HTML
|
|
||||||
7. ✅ Updated JSX to use `htmlContent`
|
|
||||||
8. ✅ Removed markdown mode (HTML only in code mode)
|
|
||||||
|
|
||||||
**Result:**
|
|
||||||
- Clean, simple, no confusion
|
|
||||||
- All changes preserved
|
|
||||||
- HTML always in sync
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Testing Checklist
|
|
||||||
|
|
||||||
### ✅ Visual Mode:
|
|
||||||
- [x] Edit blocks
|
|
||||||
- [x] Switch to code mode
|
|
||||||
- [x] See HTML with all changes
|
|
||||||
- [x] Switch back to visual
|
|
||||||
- [x] All changes still there
|
|
||||||
|
|
||||||
### ✅ Code Mode:
|
|
||||||
- [x] Edit HTML
|
|
||||||
- [x] Switch to visual mode
|
|
||||||
- [x] See blocks with all changes
|
|
||||||
- [x] Switch back to code
|
|
||||||
- [x] All changes still there
|
|
||||||
|
|
||||||
### ✅ Save:
|
|
||||||
- [x] Edit in visual mode
|
|
||||||
- [x] Save
|
|
||||||
- [x] Reload page
|
|
||||||
- [x] All changes preserved
|
|
||||||
- [x] Edit in code mode
|
|
||||||
- [x] Save
|
|
||||||
- [x] Reload page
|
|
||||||
- [x] All changes preserved
|
|
||||||
|
|
||||||
### ✅ Preview:
|
|
||||||
- [x] Edit in any mode
|
|
||||||
- [x] Switch to preview
|
|
||||||
- [x] See rendered email
|
|
||||||
- [x] All content displays
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
| Feature | Before | After |
|
|
||||||
|---------|--------|-------|
|
|
||||||
| Source of truth | Unclear | ✅ HTML |
|
|
||||||
| Mode switching | Lost changes | ✅ Preserved |
|
|
||||||
| Save logic | Complex | ✅ Simple |
|
|
||||||
| Data flow | Confusing | ✅ Clear |
|
|
||||||
| Markdown handling | Every load | ✅ One-time |
|
|
||||||
| User experience | Frustrating | ✅ Smooth |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## What Users See
|
|
||||||
|
|
||||||
### Visual Mode:
|
|
||||||
```
|
|
||||||
┌─────────────────────────────┐
|
|
||||||
│ [Add Block ▼] │
|
|
||||||
├─────────────────────────────┤
|
|
||||||
│ ┌───────────────────────┐ │
|
|
||||||
│ │ 🎨 Hero Card │ │
|
|
||||||
│ │ ## Welcome! │ │
|
|
||||||
│ │ Content here... │ │
|
|
||||||
│ └───────────────────────┘ │
|
|
||||||
│ ┌───────────────────────┐ │
|
|
||||||
│ │ 📄 Default Card │ │
|
|
||||||
│ │ More content... │ │
|
|
||||||
│ └───────────────────────┘ │
|
|
||||||
└─────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
### Code Mode:
|
|
||||||
```
|
|
||||||
┌─────────────────────────────┐
|
|
||||||
│ <div class="card card-hero">│
|
|
||||||
│ <h2>Welcome!</h2> │
|
|
||||||
│ <p>Content here...</p> │
|
|
||||||
│ </div> │
|
|
||||||
│ <div class="card"> │
|
|
||||||
│ <p>More content...</p> │
|
|
||||||
│ </div> │
|
|
||||||
└─────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
### Behind the Scenes:
|
|
||||||
```
|
|
||||||
Both modes editing the SAME HTML!
|
|
||||||
✅ No data loss
|
|
||||||
✅ Perfect sync
|
|
||||||
✅ Simple architecture
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**🎉 COMPLETE! HTML is now the single source of truth! 🚀**
|
|
||||||
|
|
||||||
**Test it:**
|
|
||||||
1. Hard refresh (Cmd+Shift+R)
|
|
||||||
2. Edit in visual mode
|
|
||||||
3. Switch to code mode → See your changes
|
|
||||||
4. Edit in code mode
|
|
||||||
5. Switch to visual mode → See your changes
|
|
||||||
6. Save → All changes preserved!
|
|
||||||
|
|
||||||
**No more confusion! No more lost changes! 🎊**
|
|
||||||
@@ -1,182 +0,0 @@
|
|||||||
# Improvements Completed
|
|
||||||
|
|
||||||
## ✅ 1. Single Source of Truth with Filter Hooks
|
|
||||||
|
|
||||||
### EventRegistry.php
|
|
||||||
Created centralized event registry with filter hook:
|
|
||||||
```php
|
|
||||||
$events = EventRegistry::get_all_events();
|
|
||||||
// Filter: woonoow_notification_events_registry
|
|
||||||
```
|
|
||||||
|
|
||||||
### DefaultTemplates.php
|
|
||||||
Added filter hooks for templates and subjects:
|
|
||||||
```php
|
|
||||||
// Filter: woonoow_email_default_templates
|
|
||||||
$templates = apply_filters('woonoow_email_default_templates', $templates);
|
|
||||||
|
|
||||||
// Filter: woonoow_email_default_subject
|
|
||||||
$subject = apply_filters('woonoow_email_default_subject', $subject, $recipient, $event);
|
|
||||||
```
|
|
||||||
|
|
||||||
### Usage Example
|
|
||||||
```php
|
|
||||||
// Add custom event
|
|
||||||
add_filter('woonoow_notification_events_registry', function($events) {
|
|
||||||
$events['custom_event'] = [
|
|
||||||
'id' => 'custom_event',
|
|
||||||
'label' => 'Custom Event',
|
|
||||||
'category' => 'custom',
|
|
||||||
'recipient_type' => 'customer',
|
|
||||||
'enabled' => true,
|
|
||||||
];
|
|
||||||
return $events;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add template for custom event
|
|
||||||
add_filter('woonoow_email_default_templates', function($templates) {
|
|
||||||
$templates['customer']['custom_event'] = '[card]Custom content[/card]';
|
|
||||||
return $templates;
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
**Result:**
|
|
||||||
- ✅ One place to manage events
|
|
||||||
- ✅ No hardcoding
|
|
||||||
- ✅ Fully extensible
|
|
||||||
- ✅ Events and templates always aligned
|
|
||||||
|
|
||||||
## ✅ 2. Card Type Selector in Markdown Toolbar
|
|
||||||
|
|
||||||
### Added Features
|
|
||||||
- **Card Insert Button** with dialog
|
|
||||||
- **Card Type Selector** dropdown with 6 types:
|
|
||||||
- Default - Standard white card
|
|
||||||
- Hero - Large header with gradient
|
|
||||||
- Success - Green success message
|
|
||||||
- Warning - Yellow warning message
|
|
||||||
- Info - Blue information card
|
|
||||||
- Basic - Minimal styling
|
|
||||||
|
|
||||||
### Implementation
|
|
||||||
- `markdown-toolbar.tsx` - Added dialog with card type selection
|
|
||||||
- Inserts properly formatted `[card type="..."]...[/card]` template
|
|
||||||
- Includes placeholder content with heading
|
|
||||||
|
|
||||||
**Result:**
|
|
||||||
- ✅ Easy card insertion
|
|
||||||
- ✅ Visual card type selection
|
|
||||||
- ✅ Better UX for markdown editing
|
|
||||||
|
|
||||||
## ✅ 3. Markdown ↔ HTML Conversion for Visual Editor
|
|
||||||
|
|
||||||
### Problem
|
|
||||||
Visual editor (RichTextEditor) was receiving markdown content directly, showing `**bold**` and `## headings` as plain text.
|
|
||||||
|
|
||||||
### Solution
|
|
||||||
|
|
||||||
#### A. Markdown → HTML (When Opening Editor)
|
|
||||||
```typescript
|
|
||||||
// EmailBuilder.tsx
|
|
||||||
const htmlContent = parseMarkdownBasics(block.content);
|
|
||||||
setEditingContent(htmlContent);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### B. HTML → Markdown (When Saving)
|
|
||||||
```typescript
|
|
||||||
// EmailBuilder.tsx
|
|
||||||
const markdownContent = htmlToMarkdown(editingContent);
|
|
||||||
return { ...block, content: markdownContent, cardType: editingCardType };
|
|
||||||
```
|
|
||||||
|
|
||||||
#### C. New Utility: `html-to-markdown.ts`
|
|
||||||
Converts rich text editor HTML output back to clean markdown:
|
|
||||||
- `<h2>` → `## `
|
|
||||||
- `<strong>` → `**...**`
|
|
||||||
- `<em>` → `*...*`
|
|
||||||
- `<p>` → double newlines
|
|
||||||
- Lists, links, etc.
|
|
||||||
|
|
||||||
**Result:**
|
|
||||||
- ✅ Visual editor shows properly formatted content
|
|
||||||
- ✅ Bold, headings, lists render correctly
|
|
||||||
- ✅ Seamless conversion between markdown and HTML
|
|
||||||
- ✅ No markdown syntax visible in visual mode
|
|
||||||
|
|
||||||
## ⚠️ 4. Newline Rendering in Preview
|
|
||||||
|
|
||||||
### Current State
|
|
||||||
The preview already uses `markdownToHtml()` which includes `parseMarkdownBasics()`:
|
|
||||||
- Single newlines → `<br>` tags
|
|
||||||
- Double newlines → separate `<p>` tags
|
|
||||||
- Lists, headings, etc. properly converted
|
|
||||||
|
|
||||||
### Implementation
|
|
||||||
```typescript
|
|
||||||
// EditTemplate.tsx - Line 202
|
|
||||||
const htmlContent = markdownToHtml(cardContent.trim());
|
|
||||||
```
|
|
||||||
|
|
||||||
The `parseMarkdownBasics()` function:
|
|
||||||
- Wraps text in `<p>` tags
|
|
||||||
- Adds `<br>` for line continuations
|
|
||||||
- Handles lists, headings, bold, italic, links
|
|
||||||
|
|
||||||
**Status:** Should be working correctly. If newlines still don't render:
|
|
||||||
1. Check if markdown has proper double newlines for paragraphs
|
|
||||||
2. Verify CSS doesn't have `white-space: nowrap`
|
|
||||||
3. Test with actual template content
|
|
||||||
|
|
||||||
## Files Modified
|
|
||||||
|
|
||||||
### Backend (PHP)
|
|
||||||
1. `/includes/Core/Notifications/EventRegistry.php` - **NEW** - Single source of truth
|
|
||||||
2. `/includes/Email/DefaultTemplates.php` - Added filter hooks
|
|
||||||
3. `/includes/Api/NotificationsController.php` - Use EventRegistry
|
|
||||||
4. `/includes/Core/Notifications/TemplateProvider.php` - Use EventRegistry
|
|
||||||
|
|
||||||
### Frontend (TypeScript/React)
|
|
||||||
1. `/admin-spa/src/components/ui/markdown-toolbar.tsx` - Card type selector dialog
|
|
||||||
2. `/admin-spa/src/components/EmailBuilder/EmailBuilder.tsx` - Markdown ↔ HTML conversion
|
|
||||||
3. `/admin-spa/src/lib/html-to-markdown.ts` - **NEW** - HTML to markdown converter
|
|
||||||
4. `/admin-spa/src/lib/markdown-utils.ts` - Export `parseMarkdownBasics`
|
|
||||||
|
|
||||||
## Testing Checklist
|
|
||||||
|
|
||||||
- [x] Filter hooks work for adding custom events
|
|
||||||
- [x] Filter hooks work for adding custom templates
|
|
||||||
- [x] Card type selector opens and inserts cards
|
|
||||||
- [x] Visual editor shows HTML (not markdown)
|
|
||||||
- [x] Markdown editor shows markdown (not HTML)
|
|
||||||
- [x] Switching between Visual ↔ Markdown preserves content
|
|
||||||
- [ ] Preview renders newlines correctly
|
|
||||||
- [ ] Bold, headings, lists render in preview
|
|
||||||
- [ ] No markdown syntax visible in preview
|
|
||||||
|
|
||||||
## Next Steps (If Needed)
|
|
||||||
|
|
||||||
1. **Test newline rendering** - Create a template with multiple paragraphs and verify preview
|
|
||||||
2. **Backend markdown processing** - Ensure WordPress shortcode handler converts markdown to HTML
|
|
||||||
3. **CSS check** - Verify email template CSS doesn't break newlines
|
|
||||||
4. **Variable replacement** - Ensure variables work in all modes
|
|
||||||
|
|
||||||
## Documentation Created
|
|
||||||
|
|
||||||
1. `FILTER_HOOKS_GUIDE.md` - Complete guide for extending events and templates
|
|
||||||
2. `SINGLE_SOURCE_OF_TRUTH.md` - Architecture documentation
|
|
||||||
3. `IMPROVEMENTS_COMPLETED.md` - This file
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
✅ **Completed:**
|
|
||||||
- Single source of truth with EventRegistry
|
|
||||||
- Full filter hook system for extensibility
|
|
||||||
- Card type selector in markdown toolbar
|
|
||||||
- Proper markdown ↔ HTML conversion for visual editor
|
|
||||||
- HTML to markdown converter
|
|
||||||
|
|
||||||
⚠️ **Needs Verification:**
|
|
||||||
- Newline rendering in preview (likely working, needs testing)
|
|
||||||
|
|
||||||
🎯 **Result:**
|
|
||||||
A fully functional, extensible notification system with seamless editing experience across markdown, visual, and preview modes.
|
|
||||||
@@ -1,221 +0,0 @@
|
|||||||
# ✅ Backend Integration Complete!
|
|
||||||
|
|
||||||
## All Issues Fixed! 🎉
|
|
||||||
|
|
||||||
Both issues have been completely resolved and the email template system is now fully functional!
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Issue #1: Template Count - FIXED ✅
|
|
||||||
|
|
||||||
**Problem:** Staff page showed "9 templates" instead of 7
|
|
||||||
|
|
||||||
**What Was Fixed:**
|
|
||||||
1. ✅ Added `recipients` array to all events in API (`NotificationsController.php`)
|
|
||||||
2. ✅ Added recipient type detection in frontend (`Templates.tsx`)
|
|
||||||
3. ✅ Filtered events by recipient type
|
|
||||||
4. ✅ Updated template count to use filtered events
|
|
||||||
|
|
||||||
**Result:**
|
|
||||||
- **Customer page:** Now shows **6 templates** (customer events only)
|
|
||||||
- **Staff page:** Now shows **7 templates** (staff events only)
|
|
||||||
|
|
||||||
**Event Breakdown:**
|
|
||||||
- **Customer events (6):** order_placed, order_processing, order_completed, order_cancelled, order_refunded, new_customer, customer_note
|
|
||||||
- **Staff events (7):** order_placed, order_processing, order_completed, order_cancelled, low_stock, out_of_stock
|
|
||||||
- **Shared events (5):** order_placed, order_processing, order_completed, order_cancelled (appear in both)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Issue #2: Old Templates - FIXED ✅
|
|
||||||
|
|
||||||
**Problem:** Backend was using old HTML templates instead of new markdown templates
|
|
||||||
|
|
||||||
**What Was Fixed:**
|
|
||||||
1. ✅ Updated `DefaultEmailTemplates.php` to use new `DefaultTemplates` class
|
|
||||||
2. ✅ Added event ID mapping for backwards compatibility
|
|
||||||
3. ✅ Added helper methods to access new templates directly
|
|
||||||
|
|
||||||
**Result:**
|
|
||||||
- ✅ All templates now use clean markdown format
|
|
||||||
- ✅ New improved content is displayed
|
|
||||||
- ✅ Backwards compatibility maintained
|
|
||||||
|
|
||||||
**Template Format Change:**
|
|
||||||
|
|
||||||
**Before (Old):**
|
|
||||||
```php
|
|
||||||
'body' => '[card type="hero"]
|
|
||||||
<h1>' . __('New Order Received!', 'woonoow') . '</h1>
|
|
||||||
<p>' . __('You have received a new order...', 'woonoow') . '</p>
|
|
||||||
[/card]'
|
|
||||||
```
|
|
||||||
|
|
||||||
**After (New):**
|
|
||||||
```php
|
|
||||||
return '[card type="hero"]
|
|
||||||
|
|
||||||
New order received!
|
|
||||||
|
|
||||||
A customer has placed a new order. Please review and process.
|
|
||||||
[/card]'
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Files Modified
|
|
||||||
|
|
||||||
### Backend Files:
|
|
||||||
1. **`includes/Core/Notifications/DefaultEmailTemplates.php`**
|
|
||||||
- Now uses `WooNooW\Email\DefaultTemplates`
|
|
||||||
- Added event mapping for compatibility
|
|
||||||
- Added helper methods
|
|
||||||
|
|
||||||
2. **`includes/Api/NotificationsController.php`**
|
|
||||||
- Added `recipients` array to all events
|
|
||||||
- Clear indication of which recipient types can receive each event
|
|
||||||
|
|
||||||
### Frontend Files:
|
|
||||||
3. **`admin-spa/src/routes/Settings/Notifications/Templates.tsx`**
|
|
||||||
- Added recipient type detection
|
|
||||||
- Added event filtering by recipient
|
|
||||||
- Updated template count display
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## How It Works Now
|
|
||||||
|
|
||||||
### 1. Template Loading Flow:
|
|
||||||
|
|
||||||
```
|
|
||||||
User opens template editor
|
|
||||||
↓
|
|
||||||
Frontend requests template from API
|
|
||||||
↓
|
|
||||||
API calls DefaultEmailTemplates::get_template()
|
|
||||||
↓
|
|
||||||
DefaultEmailTemplates maps event ID
|
|
||||||
↓
|
|
||||||
Calls new DefaultTemplates::get_all_templates()
|
|
||||||
↓
|
|
||||||
Returns new markdown template
|
|
||||||
↓
|
|
||||||
Frontend displays clean markdown format
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Event Filtering Flow:
|
|
||||||
|
|
||||||
```
|
|
||||||
User visits Customer/Staff Notifications page
|
|
||||||
↓
|
|
||||||
Frontend detects page type (customer/staff)
|
|
||||||
↓
|
|
||||||
Fetches all events from API
|
|
||||||
↓
|
|
||||||
Filters events by recipients array
|
|
||||||
↓
|
|
||||||
Displays only relevant events
|
|
||||||
↓
|
|
||||||
Shows correct template count
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Event Recipient Mapping
|
|
||||||
|
|
||||||
| Event ID | Customer | Staff | Notes |
|
|
||||||
|----------|----------|-------|-------|
|
|
||||||
| order_placed | ✅ | ✅ | Both receive notification |
|
|
||||||
| order_processing | ✅ | ✅ | Both receive notification |
|
|
||||||
| order_completed | ✅ | ✅ | Both receive notification |
|
|
||||||
| order_cancelled | ✅ | ✅ | Both receive notification |
|
|
||||||
| order_refunded | ✅ | ❌ | Customer only |
|
|
||||||
| low_stock | ❌ | ✅ | Staff only |
|
|
||||||
| out_of_stock | ❌ | ✅ | Staff only |
|
|
||||||
| new_customer | ✅ | ❌ | Customer only |
|
|
||||||
| customer_note | ✅ | ❌ | Customer only |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Testing Checklist
|
|
||||||
|
|
||||||
### ✅ Customer Page:
|
|
||||||
- [x] Navigate to Settings → Notifications → Customer → Templates
|
|
||||||
- [x] Verify badge shows correct count (6-7 templates depending on shared events)
|
|
||||||
- [x] Open any customer event template
|
|
||||||
- [x] Verify new markdown format is displayed
|
|
||||||
- [x] Verify clean, readable content (not HTML tags)
|
|
||||||
- [x] Test saving template
|
|
||||||
- [x] Test resetting template
|
|
||||||
|
|
||||||
### ✅ Staff Page:
|
|
||||||
- [x] Navigate to Settings → Notifications → Staff → Templates
|
|
||||||
- [x] Verify badge shows "7 templates"
|
|
||||||
- [x] Open any staff event template
|
|
||||||
- [x] Verify new markdown format is displayed
|
|
||||||
- [x] Verify professional staff-oriented content
|
|
||||||
- [x] Test saving template
|
|
||||||
- [x] Test resetting template
|
|
||||||
|
|
||||||
### ✅ Preview:
|
|
||||||
- [x] Open template editor
|
|
||||||
- [x] Switch to Preview tab
|
|
||||||
- [x] Verify markdown is rendered correctly
|
|
||||||
- [x] Verify buttons work
|
|
||||||
- [x] Verify cards display properly
|
|
||||||
- [x] Verify variables are replaced with sample data
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## New Template Features
|
|
||||||
|
|
||||||
All templates now include:
|
|
||||||
- ✅ Clean markdown syntax (no HTML clutter)
|
|
||||||
- ✅ Professional, friendly tone
|
|
||||||
- ✅ Clear structure with cards
|
|
||||||
- ✅ Actionable CTAs with buttons
|
|
||||||
- ✅ Complete variable support
|
|
||||||
- ✅ Horizontal rules for separation
|
|
||||||
- ✅ Checkmarks and bullet points
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Backwards Compatibility
|
|
||||||
|
|
||||||
The old `DefaultEmailTemplates` class still exists and works, but now:
|
|
||||||
- Uses new `DefaultTemplates` internally
|
|
||||||
- Maps old event IDs to new structure
|
|
||||||
- Maintains same API for existing code
|
|
||||||
- No breaking changes
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## What's Next
|
|
||||||
|
|
||||||
The email template system is now **100% complete and production-ready**!
|
|
||||||
|
|
||||||
**You can now:**
|
|
||||||
1. ✅ View correct template counts
|
|
||||||
2. ✅ See new improved templates
|
|
||||||
3. ✅ Edit templates with visual builder
|
|
||||||
4. ✅ Preview with live branding
|
|
||||||
5. ✅ Save and reset templates
|
|
||||||
6. ✅ Use on mobile (code/preview modes)
|
|
||||||
|
|
||||||
**Ready to ship! 🚀**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
| Component | Status | Notes |
|
|
||||||
|-----------|--------|-------|
|
|
||||||
| Backend Integration | ✅ Complete | Using new templates |
|
|
||||||
| Event Filtering | ✅ Complete | Correct counts |
|
|
||||||
| Template Format | ✅ Complete | Clean markdown |
|
|
||||||
| Frontend Display | ✅ Complete | All working |
|
|
||||||
| Preview System | ✅ Complete | Fully functional |
|
|
||||||
| Mobile Support | ✅ Complete | Responsive |
|
|
||||||
| Documentation | ✅ Complete | Comprehensive |
|
|
||||||
|
|
||||||
**All systems go! 🎉**
|
|
||||||
@@ -1,409 +0,0 @@
|
|||||||
# ✅ Markdown Mode - Modern 2025 Approach! 🚀
|
|
||||||
|
|
||||||
## IMPLEMENTED! User-Friendly Markdown with HTML Pivot
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## The Architecture
|
|
||||||
|
|
||||||
### **User-Facing: Markdown & Visual**
|
|
||||||
### **Behind the Scenes: HTML Pivot**
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────┐
|
|
||||||
│ USER INTERFACE │
|
|
||||||
├─────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ Visual Builder ←→ Markdown │
|
|
||||||
│ (Drag & drop) (Easy typing) │
|
|
||||||
│ │
|
|
||||||
└─────────────────────────────────────────┘
|
|
||||||
↕
|
|
||||||
┌───────────────────────┐
|
|
||||||
│ HTML PIVOT │
|
|
||||||
│ (Internal only) │
|
|
||||||
└───────────────────────┘
|
|
||||||
↕
|
|
||||||
┌───────────────────────┐
|
|
||||||
│ DATABASE (HTML) │
|
|
||||||
└───────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## How It Works
|
|
||||||
|
|
||||||
### **Complexity on Our Side, Simplicity for Users**
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// User sees: Markdown or Visual
|
|
||||||
// System handles: HTML conversion
|
|
||||||
|
|
||||||
Visual Builder ←→ HTML ←→ Markdown
|
|
||||||
↓ ↓ ↓
|
|
||||||
Blocks Pivot User-friendly
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Data Flow
|
|
||||||
|
|
||||||
### **1. Loading Template**
|
|
||||||
```
|
|
||||||
Database (HTML)
|
|
||||||
↓
|
|
||||||
Load HTML
|
|
||||||
↓
|
|
||||||
Convert to both views:
|
|
||||||
├→ HTML → Markdown (for Markdown mode)
|
|
||||||
└→ HTML → Blocks (for Visual mode)
|
|
||||||
```
|
|
||||||
|
|
||||||
### **2. Editing in Visual Mode**
|
|
||||||
```
|
|
||||||
User edits blocks
|
|
||||||
↓
|
|
||||||
Blocks → HTML (pivot)
|
|
||||||
↓
|
|
||||||
HTML → Markdown (sync)
|
|
||||||
↓
|
|
||||||
✅ All formats in sync!
|
|
||||||
```
|
|
||||||
|
|
||||||
### **3. Editing in Markdown Mode**
|
|
||||||
```
|
|
||||||
User types markdown
|
|
||||||
↓
|
|
||||||
Markdown → HTML (pivot)
|
|
||||||
↓
|
|
||||||
HTML → Blocks (sync)
|
|
||||||
↓
|
|
||||||
✅ All formats in sync!
|
|
||||||
```
|
|
||||||
|
|
||||||
### **4. Switching Modes**
|
|
||||||
```
|
|
||||||
Visual → Markdown:
|
|
||||||
Blocks → HTML → Markdown
|
|
||||||
|
|
||||||
Markdown → Visual:
|
|
||||||
Markdown → HTML → Blocks
|
|
||||||
|
|
||||||
✅ No data loss!
|
|
||||||
```
|
|
||||||
|
|
||||||
### **5. Saving**
|
|
||||||
```
|
|
||||||
Any mode
|
|
||||||
↓
|
|
||||||
HTML (always ready)
|
|
||||||
↓
|
|
||||||
Save to database
|
|
||||||
↓
|
|
||||||
✅ Simple!
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Why This Is Better
|
|
||||||
|
|
||||||
### **For Users:**
|
|
||||||
- ✅ **Markdown**: Easy to type, mobile-friendly
|
|
||||||
- ✅ **Visual**: Drag & drop, no coding needed
|
|
||||||
- ✅ **Modern**: 2025 standard (like GitHub, Notion, Slack)
|
|
||||||
- ✅ **Flexible**: Choose your preferred mode
|
|
||||||
|
|
||||||
### **For Mobile:**
|
|
||||||
```
|
|
||||||
HTML: <strong>bold</strong> ❌ Hard to type
|
|
||||||
Markdown: **bold** ✅ Easy to type!
|
|
||||||
|
|
||||||
HTML: <div class="card">...</div> ❌ Painful on phone
|
|
||||||
Markdown: [card]...[/card] ✅ Simple!
|
|
||||||
```
|
|
||||||
|
|
||||||
### **For Developers (Us):**
|
|
||||||
- ✅ HTML pivot = Database compatibility
|
|
||||||
- ✅ Clean conversion logic
|
|
||||||
- ✅ All complexity hidden from users
|
|
||||||
- ✅ Easy to maintain
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## User Experience
|
|
||||||
|
|
||||||
### **What Users See:**
|
|
||||||
|
|
||||||
#### Visual Builder:
|
|
||||||
```
|
|
||||||
┌─────────────────────────────┐
|
|
||||||
│ [Add Block ▼] Markdown │ ← Toggle button
|
|
||||||
├─────────────────────────────┤
|
|
||||||
│ ┌───────────────────────┐ │
|
|
||||||
│ │ 🎨 Hero Card │ │
|
|
||||||
│ │ ## Welcome! │ │
|
|
||||||
│ │ Content here... │ │
|
|
||||||
│ └───────────────────────┘ │
|
|
||||||
└─────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Markdown Mode:
|
|
||||||
```
|
|
||||||
┌─────────────────────────────┐
|
|
||||||
│ Visual Builder [Markdown]│ ← Toggle button
|
|
||||||
├─────────────────────────────┤
|
|
||||||
│ [card type="hero"] │
|
|
||||||
│ │
|
|
||||||
│ ## Welcome! │
|
|
||||||
│ │
|
|
||||||
│ Content here... │
|
|
||||||
│ │
|
|
||||||
│ [/card] │
|
|
||||||
└─────────────────────────────┘
|
|
||||||
|
|
||||||
💡 Write in Markdown - easy to type,
|
|
||||||
even on mobile!
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Conversion Logic
|
|
||||||
|
|
||||||
### **Visual ↔ HTML ↔ Markdown**
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Visual → HTML
|
|
||||||
blocksToHTML(blocks) → HTML
|
|
||||||
|
|
||||||
// HTML → Visual
|
|
||||||
htmlToBlocks(HTML) → blocks
|
|
||||||
|
|
||||||
// Markdown → HTML
|
|
||||||
markdownToHtml(markdown) → HTML
|
|
||||||
|
|
||||||
// HTML → Markdown
|
|
||||||
htmlToMarkdown(HTML) → markdown
|
|
||||||
```
|
|
||||||
|
|
||||||
### **Automatic Sync:**
|
|
||||||
```typescript
|
|
||||||
// When user edits in Visual mode
|
|
||||||
handleBlocksChange(newBlocks) {
|
|
||||||
setBlocks(newBlocks);
|
|
||||||
const html = blocksToHTML(newBlocks);
|
|
||||||
setHtmlContent(html); // Update pivot
|
|
||||||
setMarkdownContent(htmlToMarkdown(html)); // Sync markdown
|
|
||||||
}
|
|
||||||
|
|
||||||
// When user edits in Markdown mode
|
|
||||||
handleMarkdownChange(newMarkdown) {
|
|
||||||
setMarkdownContent(newMarkdown);
|
|
||||||
const html = markdownToHtml(newMarkdown);
|
|
||||||
setHtmlContent(html); // Update pivot
|
|
||||||
setBlocks(htmlToBlocks(html)); // Sync blocks
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## What Changed
|
|
||||||
|
|
||||||
### **Renamed:**
|
|
||||||
- ❌ "Code Mode" → ✅ "Markdown"
|
|
||||||
- ❌ `codeMode` → ✅ `markdownMode`
|
|
||||||
- ❌ `handleCodeModeToggle` → ✅ `handleMarkdownModeToggle`
|
|
||||||
|
|
||||||
### **Added:**
|
|
||||||
- ✅ `markdownContent` state
|
|
||||||
- ✅ `handleMarkdownChange` handler
|
|
||||||
- ✅ `htmlToMarkdown()` conversion
|
|
||||||
- ✅ Automatic sync between all formats
|
|
||||||
|
|
||||||
### **User-Facing:**
|
|
||||||
- ✅ "Markdown" button (not "Code Mode")
|
|
||||||
- ✅ Markdown-friendly placeholder text
|
|
||||||
- ✅ Mobile-friendly messaging
|
|
||||||
- ✅ Clear sync indicators
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Benefits Summary
|
|
||||||
|
|
||||||
| Feature | Old (HTML Code) | New (Markdown) |
|
|
||||||
|---------|-----------------|----------------|
|
|
||||||
| **Typing** | `<strong>bold</strong>` | `**bold**` ✅ |
|
|
||||||
| **Mobile** | Painful ❌ | Easy ✅ |
|
|
||||||
| **Learning curve** | High ❌ | Low ✅ |
|
|
||||||
| **Modern** | Old-school ❌ | 2025 standard ✅ |
|
|
||||||
| **User-friendly** | No ❌ | Yes ✅ |
|
|
||||||
| **Industry standard** | No ❌ | Yes (GitHub, Notion) ✅ |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Markdown Syntax Supported
|
|
||||||
|
|
||||||
### **Basic Formatting:**
|
|
||||||
```markdown
|
|
||||||
**bold**
|
|
||||||
*italic*
|
|
||||||
## Heading 2
|
|
||||||
### Heading 3
|
|
||||||
```
|
|
||||||
|
|
||||||
### **Cards:**
|
|
||||||
```markdown
|
|
||||||
[card type="hero"]
|
|
||||||
Content here
|
|
||||||
[/card]
|
|
||||||
|
|
||||||
[card type="success"]
|
|
||||||
Success message
|
|
||||||
[/card]
|
|
||||||
|
|
||||||
[card type="basic"]
|
|
||||||
Plain text
|
|
||||||
[/card]
|
|
||||||
```
|
|
||||||
|
|
||||||
### **Buttons:**
|
|
||||||
```markdown
|
|
||||||
[button url="/shop"]Shop Now[/button]
|
|
||||||
```
|
|
||||||
|
|
||||||
### **Lists:**
|
|
||||||
```markdown
|
|
||||||
✓ Checkmark item
|
|
||||||
• Bullet item
|
|
||||||
- Dash item
|
|
||||||
```
|
|
||||||
|
|
||||||
### **Horizontal Rule:**
|
|
||||||
```markdown
|
|
||||||
---
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Testing Checklist
|
|
||||||
|
|
||||||
### ✅ Visual → Markdown:
|
|
||||||
- [x] Edit in visual mode
|
|
||||||
- [x] Click "Markdown" button
|
|
||||||
- [x] See markdown with all content
|
|
||||||
- [x] Edit markdown
|
|
||||||
- [x] Click "Visual Builder"
|
|
||||||
- [x] All changes preserved
|
|
||||||
|
|
||||||
### ✅ Markdown → Visual:
|
|
||||||
- [x] Click "Markdown"
|
|
||||||
- [x] Type markdown
|
|
||||||
- [x] Click "Visual Builder"
|
|
||||||
- [x] See blocks with all content
|
|
||||||
- [x] Edit blocks
|
|
||||||
- [x] Click "Markdown"
|
|
||||||
- [x] All changes preserved
|
|
||||||
|
|
||||||
### ✅ Save & Reload:
|
|
||||||
- [x] Edit in any mode
|
|
||||||
- [x] Save
|
|
||||||
- [x] Reload page
|
|
||||||
- [x] All changes preserved
|
|
||||||
- [x] Can switch modes freely
|
|
||||||
|
|
||||||
### ✅ Mobile:
|
|
||||||
- [x] Open on mobile
|
|
||||||
- [x] Click "Markdown"
|
|
||||||
- [x] Type easily on phone
|
|
||||||
- [x] Switch to visual
|
|
||||||
- [x] Works smoothly
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Example Workflow
|
|
||||||
|
|
||||||
### **User Story: Edit on Mobile**
|
|
||||||
|
|
||||||
1. **Open template on phone**
|
|
||||||
2. **Click "Markdown" button**
|
|
||||||
3. **Type easily:**
|
|
||||||
```markdown
|
|
||||||
[card type="hero"]
|
|
||||||
|
|
||||||
## Order Confirmed!
|
|
||||||
|
|
||||||
Thank you **{customer_name}**!
|
|
||||||
|
|
||||||
[/card]
|
|
||||||
|
|
||||||
[button url="{order_url}"]View Order[/button]
|
|
||||||
```
|
|
||||||
4. **Click "Preview"** → See beautiful email
|
|
||||||
5. **Save** → Done! ✅
|
|
||||||
|
|
||||||
**Much easier than typing HTML on phone!**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Architecture Summary
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────┐
|
|
||||||
│ USER EXPERIENCE │
|
|
||||||
├─────────────────────────────────────────┤
|
|
||||||
│ Visual Builder ←→ Markdown │
|
|
||||||
│ (Easy) (Easy) │
|
|
||||||
└─────────────────────────────────────────┘
|
|
||||||
↕
|
|
||||||
┌─────────────────────────────────────────┐
|
|
||||||
│ SYSTEM COMPLEXITY │
|
|
||||||
├─────────────────────────────────────────┤
|
|
||||||
│ HTML Pivot (Internal) │
|
|
||||||
│ - Conversion logic │
|
|
||||||
│ - Format sync │
|
|
||||||
│ - Database compatibility │
|
|
||||||
└─────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
**Complexity on our side, simplicity for users! ✅**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Files Modified
|
|
||||||
|
|
||||||
### `EditTemplate.tsx`
|
|
||||||
**Changes:**
|
|
||||||
1. ✅ Added `markdownContent` state
|
|
||||||
2. ✅ Renamed `codeMode` → `markdownMode`
|
|
||||||
3. ✅ Added `handleMarkdownChange` handler
|
|
||||||
4. ✅ Updated `handleMarkdownModeToggle` for proper conversion
|
|
||||||
5. ✅ Updated `handleBlocksChange` to sync markdown
|
|
||||||
6. ✅ Changed button text to "Markdown"
|
|
||||||
7. ✅ Updated placeholder and help text
|
|
||||||
8. ✅ Import `htmlToMarkdown` function
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## What's Next
|
|
||||||
|
|
||||||
### **Test It:**
|
|
||||||
1. Hard refresh (Cmd+Shift+R)
|
|
||||||
2. Open any template
|
|
||||||
3. Click "Markdown" button
|
|
||||||
4. ✅ See markdown syntax
|
|
||||||
5. Edit markdown
|
|
||||||
6. Click "Visual Builder"
|
|
||||||
7. ✅ See your changes in blocks
|
|
||||||
8. Save
|
|
||||||
9. ✅ All preserved!
|
|
||||||
|
|
||||||
### **Try on Mobile:**
|
|
||||||
1. Open on phone
|
|
||||||
2. Click "Markdown"
|
|
||||||
3. Type easily
|
|
||||||
4. ✅ Much better than HTML!
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**🎉 DONE! Modern, user-friendly, mobile-optimized! 🚀**
|
|
||||||
|
|
||||||
**Markdown for users, HTML for system - perfect balance!**
|
|
||||||
@@ -1,316 +0,0 @@
|
|||||||
# ✅ Markdown Support Complete!
|
|
||||||
|
|
||||||
## Problem Solved! 🎉
|
|
||||||
|
|
||||||
The system now **automatically detects and converts** markdown to HTML for proper display in the editor, builder, and preview!
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## The Issue
|
|
||||||
|
|
||||||
**Before:** Markdown syntax was displayed as raw text:
|
|
||||||
- `**bold**` showed as `**bold**` instead of **bold**
|
|
||||||
- `[card]` showed as text instead of styled cards
|
|
||||||
- `[button url="..."]` showed as text instead of buttons
|
|
||||||
|
|
||||||
**Why:** TipTap editor and HTML preview can only understand HTML, not markdown.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## The Solution
|
|
||||||
|
|
||||||
### 1. **Auto-Detection** ✅
|
|
||||||
Created smart content type detection that identifies:
|
|
||||||
- Markdown patterns: `**bold**`, `[card]`, `[button]`, `---`, etc.
|
|
||||||
- HTML patterns: `<div>`, `<strong>`, etc.
|
|
||||||
|
|
||||||
### 2. **Auto-Conversion** ✅
|
|
||||||
When loading a template:
|
|
||||||
1. Detect if content is markdown or HTML
|
|
||||||
2. If markdown → convert to HTML automatically
|
|
||||||
3. Display HTML in editor/builder/preview
|
|
||||||
4. Everything renders properly!
|
|
||||||
|
|
||||||
### 3. **Seamless Experience** ✅
|
|
||||||
- Users see properly formatted content
|
|
||||||
- Bold text appears bold
|
|
||||||
- Cards appear as styled blocks
|
|
||||||
- Buttons appear as clickable buttons
|
|
||||||
- No manual conversion needed!
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## What Was Added
|
|
||||||
|
|
||||||
### New File: `markdown-utils.ts`
|
|
||||||
|
|
||||||
**Location:** `admin-spa/src/lib/markdown-utils.ts`
|
|
||||||
|
|
||||||
**Functions:**
|
|
||||||
1. `detectContentType(content)` - Detects if content is markdown or HTML
|
|
||||||
2. `markdownToHtml(markdown)` - Converts markdown to HTML
|
|
||||||
3. `htmlToMarkdown(html)` - Converts HTML back to markdown (for editing)
|
|
||||||
|
|
||||||
**Supported Markdown:**
|
|
||||||
- ✅ `**bold**` → `<strong>bold</strong>`
|
|
||||||
- ✅ `*italic*` → `<em>italic</em>`
|
|
||||||
- ✅ `# Heading` → `<h1>Heading</h1>`
|
|
||||||
- ✅ `[card]...[/card]` → `<div class="card">...</div>`
|
|
||||||
- ✅ `[button url="..."]Text[/button]` → `<a href="..." class="button">Text</a>`
|
|
||||||
- ✅ `---` → `<hr>`
|
|
||||||
- ✅ `- List item` → `<ul><li>List item</li></ul>`
|
|
||||||
- ✅ `• Bullet` → `<ul><li>Bullet</li></ul>`
|
|
||||||
- ✅ `✓ Checkmark` → `<ul><li>Checkmark</li></ul>`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## How It Works
|
|
||||||
|
|
||||||
### Loading Flow:
|
|
||||||
|
|
||||||
```
|
|
||||||
1. User opens template editor
|
|
||||||
↓
|
|
||||||
2. Template loaded from backend (markdown format)
|
|
||||||
↓
|
|
||||||
3. detectContentType() checks if markdown
|
|
||||||
↓
|
|
||||||
4. If markdown: markdownToHtml() converts to HTML
|
|
||||||
↓
|
|
||||||
5. HTML displayed in editor/builder
|
|
||||||
↓
|
|
||||||
6. User sees properly formatted content!
|
|
||||||
```
|
|
||||||
|
|
||||||
### Saving Flow:
|
|
||||||
|
|
||||||
```
|
|
||||||
1. User edits in visual builder or code mode
|
|
||||||
↓
|
|
||||||
2. Content is already in HTML format
|
|
||||||
↓
|
|
||||||
3. Save HTML to database
|
|
||||||
↓
|
|
||||||
4. Next time: auto-convert again if needed
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Files Modified
|
|
||||||
|
|
||||||
### 1. **Created: `admin-spa/src/lib/markdown-utils.ts`**
|
|
||||||
- Content type detection
|
|
||||||
- Markdown → HTML conversion
|
|
||||||
- HTML → Markdown conversion
|
|
||||||
- Full markdown syntax support
|
|
||||||
|
|
||||||
### 2. **Updated: `admin-spa/src/routes/Settings/Notifications/EditTemplate.tsx`**
|
|
||||||
- Added import: `import { detectContentType, markdownToHtml } from '@/lib/markdown-utils'`
|
|
||||||
- Added auto-detection in `useEffect` when template loads
|
|
||||||
- Converts markdown to HTML before displaying
|
|
||||||
|
|
||||||
**Key Changes:**
|
|
||||||
```typescript
|
|
||||||
// Detect if content is markdown or HTML
|
|
||||||
const contentType = detectContentType(template.body || '');
|
|
||||||
|
|
||||||
let processedBody = template.body || '';
|
|
||||||
|
|
||||||
// If markdown, convert to HTML for display
|
|
||||||
if (contentType === 'markdown') {
|
|
||||||
processedBody = markdownToHtml(template.body || '');
|
|
||||||
}
|
|
||||||
|
|
||||||
setBody(processedBody);
|
|
||||||
setBlocks(htmlToBlocks(processedBody));
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## What Users See Now
|
|
||||||
|
|
||||||
### Before (Broken):
|
|
||||||
```
|
|
||||||
**Order Number:** #{order_number}
|
|
||||||
**Customer:** {customer_name}
|
|
||||||
**Order Date:** {order_date}
|
|
||||||
```
|
|
||||||
|
|
||||||
### After (Fixed):
|
|
||||||
```
|
|
||||||
Order Number: #12345
|
|
||||||
Customer: John Doe
|
|
||||||
Order Date: 11/14/2025
|
|
||||||
```
|
|
||||||
(With proper bold formatting!)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Testing Checklist
|
|
||||||
|
|
||||||
### ✅ Visual Builder:
|
|
||||||
- [x] Open any template
|
|
||||||
- [x] Markdown is converted to HTML
|
|
||||||
- [x] Bold text appears bold
|
|
||||||
- [x] Cards appear as styled blocks
|
|
||||||
- [x] Can edit in rich text editor
|
|
||||||
|
|
||||||
### ✅ Code Mode:
|
|
||||||
- [x] Switch to code mode
|
|
||||||
- [x] See HTML (not raw markdown)
|
|
||||||
- [x] Can edit HTML directly
|
|
||||||
- [x] Changes reflected in preview
|
|
||||||
|
|
||||||
### ✅ Preview:
|
|
||||||
- [x] Switch to preview tab
|
|
||||||
- [x] Everything renders correctly
|
|
||||||
- [x] Cards styled properly
|
|
||||||
- [x] Buttons clickable
|
|
||||||
- [x] Variables replaced
|
|
||||||
|
|
||||||
### ✅ Saving:
|
|
||||||
- [x] Save template
|
|
||||||
- [x] Reload page
|
|
||||||
- [x] Content still displays correctly
|
|
||||||
- [x] No data loss
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Markdown Syntax Reference
|
|
||||||
|
|
||||||
### Text Formatting:
|
|
||||||
```markdown
|
|
||||||
**Bold text**
|
|
||||||
*Italic text*
|
|
||||||
# Heading 1
|
|
||||||
## Heading 2
|
|
||||||
### Heading 3
|
|
||||||
```
|
|
||||||
|
|
||||||
### Cards:
|
|
||||||
```markdown
|
|
||||||
[card]
|
|
||||||
Default card content
|
|
||||||
[/card]
|
|
||||||
|
|
||||||
[card type="hero"]
|
|
||||||
Hero card with gradient
|
|
||||||
[/card]
|
|
||||||
|
|
||||||
[card type="success"]
|
|
||||||
Success card
|
|
||||||
[/card]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Buttons:
|
|
||||||
```markdown
|
|
||||||
[button url="{order_url}"]View Order[/button]
|
|
||||||
|
|
||||||
[button url="#" style="outline"]Secondary Action[/button]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Lists:
|
|
||||||
```markdown
|
|
||||||
- List item 1
|
|
||||||
- List item 2
|
|
||||||
• Bullet point
|
|
||||||
✓ Checkmark item
|
|
||||||
```
|
|
||||||
|
|
||||||
### Horizontal Rules:
|
|
||||||
```markdown
|
|
||||||
---
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Benefits
|
|
||||||
|
|
||||||
### For Users:
|
|
||||||
- ✅ Templates display correctly immediately
|
|
||||||
- ✅ No manual conversion needed
|
|
||||||
- ✅ Can edit visually or in code
|
|
||||||
- ✅ What you see is what you get
|
|
||||||
|
|
||||||
### For Developers:
|
|
||||||
- ✅ Clean markdown in database
|
|
||||||
- ✅ Automatic conversion
|
|
||||||
- ✅ Backwards compatible
|
|
||||||
- ✅ Easy to maintain
|
|
||||||
|
|
||||||
### For Store Owners:
|
|
||||||
- ✅ Professional emails out of the box
|
|
||||||
- ✅ Easy to customize
|
|
||||||
- ✅ No technical knowledge required
|
|
||||||
- ✅ Works immediately
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Edge Cases Handled
|
|
||||||
|
|
||||||
### 1. **Mixed Content**
|
|
||||||
If content has both HTML and markdown:
|
|
||||||
- Detection favors markdown if `[card]` or `[button]` syntax present
|
|
||||||
- Otherwise uses HTML
|
|
||||||
|
|
||||||
### 2. **Empty Content**
|
|
||||||
- Returns empty string safely
|
|
||||||
- No errors
|
|
||||||
|
|
||||||
### 3. **Invalid Markdown**
|
|
||||||
- Falls back to treating as HTML
|
|
||||||
- No breaking errors
|
|
||||||
|
|
||||||
### 4. **Already HTML**
|
|
||||||
- Detects and skips conversion
|
|
||||||
- No double-processing
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Performance
|
|
||||||
|
|
||||||
**Impact:** Minimal
|
|
||||||
- Detection: ~1ms
|
|
||||||
- Conversion: ~5-10ms for typical template
|
|
||||||
- Only runs once on template load
|
|
||||||
- No performance issues
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Backwards Compatibility
|
|
||||||
|
|
||||||
**100% Compatible:**
|
|
||||||
- Old HTML templates still work
|
|
||||||
- New markdown templates work
|
|
||||||
- Mixed content works
|
|
||||||
- No breaking changes
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
| Feature | Status | Notes |
|
|
||||||
|---------|--------|-------|
|
|
||||||
| Markdown Detection | ✅ Complete | Smart pattern matching |
|
|
||||||
| Auto-Conversion | ✅ Complete | Seamless |
|
|
||||||
| Visual Builder | ✅ Working | Displays HTML |
|
|
||||||
| Code Mode | ✅ Working | Shows HTML |
|
|
||||||
| Preview | ✅ Working | Renders correctly |
|
|
||||||
| Saving | ✅ Working | No data loss |
|
|
||||||
| Performance | ✅ Optimal | <10ms overhead |
|
|
||||||
| Compatibility | ✅ 100% | All formats work |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## What's Next
|
|
||||||
|
|
||||||
**Nothing!** The system is complete and working! 🎉
|
|
||||||
|
|
||||||
Users can now:
|
|
||||||
1. ✅ Load templates (auto-converted)
|
|
||||||
2. ✅ Edit visually or in code
|
|
||||||
3. ✅ Preview with branding
|
|
||||||
4. ✅ Save changes
|
|
||||||
5. ✅ Everything works!
|
|
||||||
|
|
||||||
**Ready to use! 🚀**
|
|
||||||
@@ -1,170 +0,0 @@
|
|||||||
# Markdown Syntax & Variables - Analysis & Recommendations
|
|
||||||
|
|
||||||
## Current Issues
|
|
||||||
|
|
||||||
### 1. Card & Button Syntax
|
|
||||||
**Current:**
|
|
||||||
```markdown
|
|
||||||
[card type="hero"]
|
|
||||||
Content here
|
|
||||||
[/card]
|
|
||||||
|
|
||||||
[button url="https://example.com" style="solid"]Click me[/button]
|
|
||||||
```
|
|
||||||
|
|
||||||
**Problem:** Not standard Markdown - uses WordPress-style shortcodes
|
|
||||||
|
|
||||||
### 2. Variable Naming Mismatch
|
|
||||||
**Template uses:** `{order_item_table}` (singular)
|
|
||||||
**Preview defines:** `order_items_table` (plural)
|
|
||||||
**Result:** Variable not replaced, shows as `{orderitemtable}` (underscores removed by some HTML sanitizer)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## All Variables Used in Templates
|
|
||||||
|
|
||||||
### Order Variables
|
|
||||||
- `{order_number}` - Order ID
|
|
||||||
- `{order_date}` - Order date
|
|
||||||
- `{order_total}` - Total amount
|
|
||||||
- `{order_status}` - Current status
|
|
||||||
- `{order_url}` - Link to view order
|
|
||||||
- `{order_item_table}` ⚠️ **MISMATCH** - Should be `order_items_table`
|
|
||||||
|
|
||||||
### Customer Variables
|
|
||||||
- `{customer_name}` - Customer full name
|
|
||||||
- `{customer_email}` - Customer email
|
|
||||||
- `{customer_username}` - Username (for new accounts)
|
|
||||||
- `{customer_password}` - Temporary password (for new accounts)
|
|
||||||
|
|
||||||
### Store Variables
|
|
||||||
- `{store_name}` - Store name
|
|
||||||
- `{store_url}` - Store URL
|
|
||||||
- `{store_email}` - Store contact email
|
|
||||||
|
|
||||||
### Payment Variables
|
|
||||||
- `{payment_method}` - Payment method used
|
|
||||||
- `{payment_status}` - Payment status
|
|
||||||
- `{transaction_id}` - Transaction ID
|
|
||||||
|
|
||||||
### Shipping Variables
|
|
||||||
- `{shipping_address}` - Full shipping address
|
|
||||||
- `{tracking_number}` - Shipment tracking number
|
|
||||||
- `{carrier}` - Shipping carrier
|
|
||||||
|
|
||||||
### Date Variables
|
|
||||||
- `{completion_date}` - Order completion date
|
|
||||||
- `{cancellation_date}` - Order cancellation date
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Recommendations
|
|
||||||
|
|
||||||
### Option 1: Keep Current Syntax (Easiest)
|
|
||||||
**Pros:**
|
|
||||||
- No changes needed
|
|
||||||
- Users already familiar
|
|
||||||
- Clear boundaries for cards
|
|
||||||
|
|
||||||
**Cons:**
|
|
||||||
- Not standard Markdown
|
|
||||||
- Verbose
|
|
||||||
|
|
||||||
**Action:** Just fix the variable mismatch
|
|
||||||
|
|
||||||
### Option 2: Simplified Shortcode
|
|
||||||
```markdown
|
|
||||||
[card:hero]
|
|
||||||
Content here
|
|
||||||
[/card]
|
|
||||||
|
|
||||||
[button:solid](https://example.com)Click me[/button]
|
|
||||||
```
|
|
||||||
|
|
||||||
**Pros:**
|
|
||||||
- Shorter, cleaner
|
|
||||||
- Still clear
|
|
||||||
|
|
||||||
**Cons:**
|
|
||||||
- Still not standard Markdown
|
|
||||||
- Requires converter changes
|
|
||||||
|
|
||||||
### Option 3: HTML + Markdown (Hybrid)
|
|
||||||
```html
|
|
||||||
<div class="card card-hero">
|
|
||||||
|
|
||||||
**Content** with markdown
|
|
||||||
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a href="url" class="button">Click me</a>
|
|
||||||
```
|
|
||||||
|
|
||||||
**Pros:**
|
|
||||||
- Standard Markdown allows inline HTML
|
|
||||||
- No custom parsing needed
|
|
||||||
|
|
||||||
**Cons:**
|
|
||||||
- Verbose
|
|
||||||
- Less user-friendly
|
|
||||||
|
|
||||||
### Option 4: Attributes Syntax (Most Markdown-like)
|
|
||||||
```markdown
|
|
||||||
> **Order Number:** #{order_number}
|
|
||||||
> **Order Date:** {order_date}
|
|
||||||
{: .card .card-hero}
|
|
||||||
|
|
||||||
[Click me](https://example.com){: .button .button-solid}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Pros:**
|
|
||||||
- More Markdown-like
|
|
||||||
- Compact
|
|
||||||
|
|
||||||
**Cons:**
|
|
||||||
- Complex to parse
|
|
||||||
- Not widely supported
|
|
||||||
- Users may not understand
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Recommended Action Plan
|
|
||||||
|
|
||||||
### Immediate Fixes (Priority 1)
|
|
||||||
1. ✅ **Fix `<br>` rendering** - DONE!
|
|
||||||
2. ⚠️ **Fix variable mismatch:**
|
|
||||||
- Change `order_item_table` → `order_items_table` in DefaultTemplates.php
|
|
||||||
- OR change `order_items_table` → `order_item_table` in EditTemplate.tsx preview
|
|
||||||
3. **Add all missing variables to preview sample data**
|
|
||||||
|
|
||||||
### Short-term (Priority 2)
|
|
||||||
1. **Document all variables** - Create user-facing documentation
|
|
||||||
2. **Add variable autocomplete** in markdown editor
|
|
||||||
3. **Add variable validation** - warn if variable doesn't exist
|
|
||||||
|
|
||||||
### Long-term (Priority 3)
|
|
||||||
1. **Consider syntax improvements** - Get user feedback first
|
|
||||||
2. **Add visual card/button inserter** - UI buttons to insert syntax
|
|
||||||
3. **Add syntax highlighting** in markdown editor
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Variable Replacement Issue
|
|
||||||
|
|
||||||
The underscore removal (`{order_item_table}` → `{orderitemtable}`) suggests HTML sanitization is happening somewhere. Need to check:
|
|
||||||
|
|
||||||
1. **Frontend:** DOMPurify or similar sanitizer?
|
|
||||||
2. **Backend:** WordPress `wp_kses()` or similar?
|
|
||||||
3. **Email client:** Some email clients strip underscores?
|
|
||||||
|
|
||||||
**Solution:** Use consistent naming without underscores OR fix sanitizer to preserve variable syntax.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Next Steps
|
|
||||||
|
|
||||||
1. Fix variable naming mismatch
|
|
||||||
2. Test all variables in preview
|
|
||||||
3. Document syntax for users
|
|
||||||
4. Get feedback on syntax preferences
|
|
||||||
5. Consider improvements based on feedback
|
|
||||||
@@ -1,252 +0,0 @@
|
|||||||
# ✨ New Markdown Syntax - Implemented!
|
|
||||||
|
|
||||||
## 🎉 What's New
|
|
||||||
|
|
||||||
### Cleaner, More Intuitive Syntax
|
|
||||||
|
|
||||||
**Before (Old Syntax):**
|
|
||||||
```markdown
|
|
||||||
[card type="hero"]
|
|
||||||
Content here
|
|
||||||
[/card]
|
|
||||||
|
|
||||||
[button url="https://example.com" style="solid"]Click me[/button]
|
|
||||||
```
|
|
||||||
|
|
||||||
**After (New Syntax):**
|
|
||||||
```markdown
|
|
||||||
[card:hero]
|
|
||||||
Content here
|
|
||||||
[/card]
|
|
||||||
|
|
||||||
[button:solid](https://example.com)Click me[/button]
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📝 Complete Syntax Guide
|
|
||||||
|
|
||||||
### Cards
|
|
||||||
|
|
||||||
**Basic Card:**
|
|
||||||
```markdown
|
|
||||||
[card]
|
|
||||||
Your content here
|
|
||||||
[/card]
|
|
||||||
```
|
|
||||||
|
|
||||||
**Styled Cards:**
|
|
||||||
```markdown
|
|
||||||
[card:hero]
|
|
||||||
Large header with gradient
|
|
||||||
[/card]
|
|
||||||
|
|
||||||
[card:success]
|
|
||||||
Success message
|
|
||||||
[/card]
|
|
||||||
|
|
||||||
[card:warning]
|
|
||||||
Warning message
|
|
||||||
[/card]
|
|
||||||
|
|
||||||
[card:info]
|
|
||||||
Information card
|
|
||||||
[/card]
|
|
||||||
|
|
||||||
[card:basic]
|
|
||||||
Minimal styling
|
|
||||||
[/card]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Buttons
|
|
||||||
|
|
||||||
**Solid Button:**
|
|
||||||
```markdown
|
|
||||||
[button:solid](https://example.com)Click me[/button]
|
|
||||||
```
|
|
||||||
|
|
||||||
**Outline Button:**
|
|
||||||
```markdown
|
|
||||||
[button:outline](https://example.com)Click me[/button]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Images
|
|
||||||
|
|
||||||
**Standard Markdown:**
|
|
||||||
```markdown
|
|
||||||

|
|
||||||
```
|
|
||||||
|
|
||||||
### Text Formatting
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
**Bold text**
|
|
||||||
*Italic text*
|
|
||||||
# Heading 1
|
|
||||||
## Heading 2
|
|
||||||
### Heading 3
|
|
||||||
|
|
||||||
- Bullet list
|
|
||||||
- Another item
|
|
||||||
|
|
||||||
1. Numbered list
|
|
||||||
2. Another item
|
|
||||||
|
|
||||||
[Link text](https://example.com)
|
|
||||||
|
|
||||||
---
|
|
||||||
Horizontal rule
|
|
||||||
```
|
|
||||||
|
|
||||||
## 🔧 Markdown Toolbar
|
|
||||||
|
|
||||||
The toolbar now includes:
|
|
||||||
- **Card** button - Insert cards with type selector
|
|
||||||
- **Button** button - Insert buttons with style selector
|
|
||||||
- **Image** button - Insert image template
|
|
||||||
- All standard formatting tools (Bold, Italic, Headings, etc.)
|
|
||||||
|
|
||||||
## 🔄 Backward Compatibility
|
|
||||||
|
|
||||||
The old syntax still works! Both formats are supported:
|
|
||||||
|
|
||||||
**Old Format (Still Works):**
|
|
||||||
```markdown
|
|
||||||
[card type="hero"]...[/card]
|
|
||||||
[button url="..." style="solid"]...[/button]
|
|
||||||
```
|
|
||||||
|
|
||||||
**New Format (Recommended):**
|
|
||||||
```markdown
|
|
||||||
[card:hero]...[/card]
|
|
||||||
[button:solid](url)...[/button]
|
|
||||||
```
|
|
||||||
|
|
||||||
## 📊 All Available Variables
|
|
||||||
|
|
||||||
### Order Variables
|
|
||||||
- `{order_number}` - Order ID
|
|
||||||
- `{order_date}` - Order date
|
|
||||||
- `{order_total}` - Total amount
|
|
||||||
- `{order_status}` - Current status
|
|
||||||
- `{order_url}` - Link to view order
|
|
||||||
- `{order_items_list}` - Items as formatted list
|
|
||||||
- `{order_items_table}` - Items as formatted table ✅ FIXED
|
|
||||||
|
|
||||||
### Customer Variables
|
|
||||||
- `{customer_name}` - Customer full name
|
|
||||||
- `{customer_email}` - Customer email
|
|
||||||
- `{customer_phone}` - Phone number
|
|
||||||
- `{customer_username}` - Username
|
|
||||||
- `{customer_password}` - Temporary password
|
|
||||||
|
|
||||||
### Store Variables
|
|
||||||
- `{store_name}` - Store name
|
|
||||||
- `{store_url}` - Store URL
|
|
||||||
- `{store_email}` - Store contact email
|
|
||||||
- `{support_email}` - Support email
|
|
||||||
|
|
||||||
### Payment Variables
|
|
||||||
- `{payment_method}` - Payment method used
|
|
||||||
- `{payment_status}` - Payment status
|
|
||||||
- `{payment_url}` - Payment link
|
|
||||||
- `{payment_date}` - Payment date
|
|
||||||
- `{transaction_id}` - Transaction ID
|
|
||||||
- `{refund_amount}` - Refund amount
|
|
||||||
|
|
||||||
### Shipping Variables
|
|
||||||
- `{shipping_address}` - Full shipping address
|
|
||||||
- `{billing_address}` - Full billing address
|
|
||||||
- `{tracking_number}` - Shipment tracking number
|
|
||||||
- `{tracking_url}` - Tracking link
|
|
||||||
- `{shipping_carrier}` - Shipping carrier
|
|
||||||
- `{shipping_method}` - Shipping method
|
|
||||||
|
|
||||||
### Date Variables
|
|
||||||
- `{completion_date}` - Order completion date
|
|
||||||
- `{cancellation_date}` - Order cancellation date
|
|
||||||
- `{current_year}` - Current year
|
|
||||||
|
|
||||||
### URL Variables
|
|
||||||
- `{review_url}` - Product review link
|
|
||||||
- `{shop_url}` - Shop homepage
|
|
||||||
- `{my_account_url}` - Customer account
|
|
||||||
- `{payment_retry_url}` - Retry payment
|
|
||||||
- `{vip_dashboard_url}` - VIP dashboard
|
|
||||||
|
|
||||||
## ✅ What's Fixed
|
|
||||||
|
|
||||||
1. ✅ **Newline rendering** - `<br>` tags now generated correctly
|
|
||||||
2. ✅ **Variable mismatch** - `order_items_table` fixed
|
|
||||||
3. ✅ **Cleaner syntax** - New `[card:type]` and `[button:style](url)` format
|
|
||||||
4. ✅ **Toolbar enhancements** - Added Image and Button insert buttons
|
|
||||||
5. ✅ **Backward compatibility** - Old syntax still works
|
|
||||||
|
|
||||||
## 🚀 Usage Examples
|
|
||||||
|
|
||||||
### Order Confirmation Email
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
[card:hero]
|
|
||||||
|
|
||||||
## Thank you for your order, {customer_name}!
|
|
||||||
|
|
||||||
We've received your order and will begin processing it right away.
|
|
||||||
|
|
||||||
[/card]
|
|
||||||
|
|
||||||
[card]
|
|
||||||
|
|
||||||
**Order Number:** #{order_number}
|
|
||||||
**Order Date:** {order_date}
|
|
||||||
**Order Total:** {order_total}
|
|
||||||
|
|
||||||
[/card]
|
|
||||||
|
|
||||||
[card]
|
|
||||||
|
|
||||||
{order_items_table}
|
|
||||||
|
|
||||||
[/card]
|
|
||||||
|
|
||||||
[button:solid]({order_url})View Order Details[/button]
|
|
||||||
|
|
||||||
[card:basic]
|
|
||||||
|
|
||||||
Questions? Contact us at {support_email}
|
|
||||||
|
|
||||||
[/card]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Shipping Notification
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
[card:info]
|
|
||||||
|
|
||||||
## Your order is on the way! 📦
|
|
||||||
|
|
||||||
Tracking Number: **{tracking_number}**
|
|
||||||
|
|
||||||
[/card]
|
|
||||||
|
|
||||||
[button:solid]({tracking_url})Track Your Package[/button]
|
|
||||||
```
|
|
||||||
|
|
||||||
## 💡 Tips
|
|
||||||
|
|
||||||
1. **Use card types** to highlight important information
|
|
||||||
2. **Variables** are automatically replaced with real data
|
|
||||||
3. **Newlines work!** Just press Enter to create line breaks
|
|
||||||
4. **Use the toolbar** for quick formatting
|
|
||||||
5. **Preview** your changes before saving
|
|
||||||
|
|
||||||
## 🎨 Card Types
|
|
||||||
|
|
||||||
- **default** - Standard white card
|
|
||||||
- **hero** - Large gradient header (perfect for main message)
|
|
||||||
- **success** - Green (order confirmed, payment received)
|
|
||||||
- **warning** - Yellow (action required, pending)
|
|
||||||
- **info** - Blue (shipping updates, information)
|
|
||||||
- **basic** - Minimal (footer, contact info)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Enjoy the new syntax! 🎉**
|
|
||||||
@@ -1,675 +0,0 @@
|
|||||||
# Notification System Audit Report
|
|
||||||
|
|
||||||
**Date:** November 11, 2025, 6:35 PM (GMT+7)
|
|
||||||
**Auditor:** System Analysis
|
|
||||||
**Scope:** Complete notification feature assessment and industry comparison
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔍 Current State Analysis
|
|
||||||
|
|
||||||
### What We Built
|
|
||||||
|
|
||||||
**1. Admin Notifications Only**
|
|
||||||
- ✅ Email notifications for admins
|
|
||||||
- ✅ Push notifications for admins
|
|
||||||
- ✅ Activity log for admins
|
|
||||||
- ✅ Notification settings UI for admins
|
|
||||||
|
|
||||||
**2. Architecture**
|
|
||||||
- Backend: `includes/Core/Notifications/`
|
|
||||||
- Frontend: `admin-spa/src/routes/Settings/Notifications/`
|
|
||||||
- API: `includes/Api/NotificationsController.php`
|
|
||||||
- Database: Activity log table
|
|
||||||
|
|
||||||
**3. Features**
|
|
||||||
- Global channel toggles (email, push)
|
|
||||||
- Per-event channel toggles
|
|
||||||
- Push notification subscription
|
|
||||||
- Activity logging
|
|
||||||
- Template management (planned)
|
|
||||||
|
|
||||||
### Critical Finding: **Admin-Only Focus**
|
|
||||||
|
|
||||||
**Effort Investment:**
|
|
||||||
- 15+ files created/modified
|
|
||||||
- 3000+ lines of code
|
|
||||||
- Complete UI/UX system
|
|
||||||
- REST API infrastructure
|
|
||||||
- Database tables
|
|
||||||
|
|
||||||
**Current Benefit:** Admin alerts only
|
|
||||||
|
|
||||||
**Missed Opportunity:** Customer notifications (larger user base, higher impact)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🌍 Industry Research: Modern E-commerce Platforms
|
|
||||||
|
|
||||||
### 1. Shopify
|
|
||||||
|
|
||||||
**Admin Notifications:**
|
|
||||||
- Settings → Notifications → Staff notifications
|
|
||||||
- Email notifications for orders, inventory, etc.
|
|
||||||
- Push notifications via Shopify mobile app
|
|
||||||
- Separate from customer notifications
|
|
||||||
|
|
||||||
**Customer Notifications:**
|
|
||||||
- Settings → Notifications → Customer notifications
|
|
||||||
- Order confirmation, shipping updates, etc.
|
|
||||||
- Email templates with drag-and-drop editor
|
|
||||||
- SMS notifications (addon)
|
|
||||||
- Push notifications (via Shopify mobile app)
|
|
||||||
|
|
||||||
**Key Insight:** **Separate sections, but same infrastructure**
|
|
||||||
|
|
||||||
**UI Structure:**
|
|
||||||
```
|
|
||||||
Settings → Notifications
|
|
||||||
├── Staff notifications
|
|
||||||
│ ├── Orders (New order, Cancelled order, etc.)
|
|
||||||
│ ├── Products (Low stock, Out of stock)
|
|
||||||
│ └── Customers (New customer)
|
|
||||||
└── Customer notifications
|
|
||||||
├── Order notifications (Confirmation, Shipped, Delivered)
|
|
||||||
├── Shipping notifications (Tracking updates)
|
|
||||||
├── Marketing (Abandoned cart, Promotions)
|
|
||||||
└── Account (Welcome, Password reset)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2. WooCommerce (Default)
|
|
||||||
|
|
||||||
**Admin Notifications:**
|
|
||||||
- WooCommerce → Settings → Emails
|
|
||||||
- New order, Cancelled order, Low stock, etc.
|
|
||||||
- Email only (no push)
|
|
||||||
|
|
||||||
**Customer Notifications:**
|
|
||||||
- Same location: WooCommerce → Settings → Emails
|
|
||||||
- Order confirmation, Processing, Completed, etc.
|
|
||||||
- Email only (no push)
|
|
||||||
- **Mixed together in one list** (confusing UX)
|
|
||||||
|
|
||||||
**Key Insight:** **Poor UX - admin and customer emails mixed**
|
|
||||||
|
|
||||||
**UI Structure:**
|
|
||||||
```
|
|
||||||
WooCommerce → Settings → Emails
|
|
||||||
├── New order (Admin)
|
|
||||||
├── Cancelled order (Admin)
|
|
||||||
├── Failed order (Admin)
|
|
||||||
├── Order on-hold (Customer)
|
|
||||||
├── Processing order (Customer)
|
|
||||||
├── Completed order (Customer)
|
|
||||||
├── Refunded order (Customer)
|
|
||||||
├── Customer invoice (Customer)
|
|
||||||
├── Customer note (Customer)
|
|
||||||
├── Reset password (Customer)
|
|
||||||
└── New account (Customer)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Problem:** Hard to distinguish admin vs customer emails
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3. BigCommerce
|
|
||||||
|
|
||||||
**Admin Notifications:**
|
|
||||||
- Settings → Store Setup → Email Notifications → Staff
|
|
||||||
- Order notifications
|
|
||||||
- Low stock alerts
|
|
||||||
- Email only
|
|
||||||
|
|
||||||
**Customer Notifications:**
|
|
||||||
- Settings → Store Setup → Email Notifications → Customer
|
|
||||||
- Order status updates
|
|
||||||
- Shipping notifications
|
|
||||||
- Account notifications
|
|
||||||
- **Separate tab, clear separation**
|
|
||||||
|
|
||||||
**Key Insight:** **Clear separation improves UX**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 4. Magento
|
|
||||||
|
|
||||||
**Admin Notifications:**
|
|
||||||
- Stores → Configuration → Sales Emails
|
|
||||||
- Admin-specific emails
|
|
||||||
- System alerts
|
|
||||||
|
|
||||||
**Customer Notifications:**
|
|
||||||
- Stores → Configuration → Sales Emails
|
|
||||||
- Customer order emails
|
|
||||||
- Transactional emails
|
|
||||||
- Marketing emails (separate module)
|
|
||||||
|
|
||||||
**Key Insight:** **Same infrastructure, different recipients**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 5. Stripe Dashboard (Payment Platform)
|
|
||||||
|
|
||||||
**Admin Notifications:**
|
|
||||||
- Settings → Notifications → Email notifications
|
|
||||||
- Payment events, disputes, etc.
|
|
||||||
- Webhook notifications (developer)
|
|
||||||
|
|
||||||
**Customer Notifications:**
|
|
||||||
- Settings → Customer emails
|
|
||||||
- Receipt emails
|
|
||||||
- Invoice emails
|
|
||||||
- Payment confirmation
|
|
||||||
|
|
||||||
**Key Insight:** **Clear separation, but shared templates**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📊 Industry Best Practices
|
|
||||||
|
|
||||||
### 1. Notification Architecture
|
|
||||||
|
|
||||||
**Unified System, Separate UIs:**
|
|
||||||
```
|
|
||||||
Notification System (Core)
|
|
||||||
├── Channels (Email, Push, SMS)
|
|
||||||
├── Events (Order, Product, Customer)
|
|
||||||
├── Templates (Shared)
|
|
||||||
└── Delivery Engine
|
|
||||||
|
|
||||||
Admin UI
|
|
||||||
├── Staff notifications
|
|
||||||
└── Activity log
|
|
||||||
|
|
||||||
Customer UI
|
|
||||||
├── Customer notifications
|
|
||||||
└── Notification preferences (customer-facing)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Benefits:**
|
|
||||||
- ✅ Reusable infrastructure
|
|
||||||
- ✅ Consistent behavior
|
|
||||||
- ✅ Easier maintenance
|
|
||||||
- ✅ Shared templates
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2. UI/UX Patterns
|
|
||||||
|
|
||||||
**Pattern A: Separate Tabs (Shopify, BigCommerce)**
|
|
||||||
```
|
|
||||||
Notifications
|
|
||||||
├── [Tab] Staff Notifications
|
|
||||||
│ └── Events list with toggles
|
|
||||||
└── [Tab] Customer Notifications
|
|
||||||
└── Events list with toggles
|
|
||||||
```
|
|
||||||
|
|
||||||
**Pattern B: Separate Pages (Better for complex systems)**
|
|
||||||
```
|
|
||||||
Settings
|
|
||||||
├── Staff Notifications
|
|
||||||
│ ├── Channels
|
|
||||||
│ ├── Events
|
|
||||||
│ └── Templates
|
|
||||||
└── Customer Notifications
|
|
||||||
├── Channels
|
|
||||||
├── Events
|
|
||||||
└── Templates
|
|
||||||
```
|
|
||||||
|
|
||||||
**Pattern C: Recipient Filter (WooCommerce - NOT recommended)**
|
|
||||||
```
|
|
||||||
Notifications
|
|
||||||
└── All notifications (mixed)
|
|
||||||
└── Filter by recipient
|
|
||||||
```
|
|
||||||
|
|
||||||
**Recommendation:** **Pattern B** - Separate pages with shared components
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3. Customer Notification Types
|
|
||||||
|
|
||||||
**Transactional (High Priority):**
|
|
||||||
- Order confirmation
|
|
||||||
- Order status updates (Processing, Shipped, Delivered)
|
|
||||||
- Payment confirmation
|
|
||||||
- Refund notification
|
|
||||||
- Shipping updates with tracking
|
|
||||||
|
|
||||||
**Account (Medium Priority):**
|
|
||||||
- Welcome email
|
|
||||||
- Password reset
|
|
||||||
- Account verification
|
|
||||||
- Profile updates
|
|
||||||
|
|
||||||
**Marketing (Low Priority, Optional):**
|
|
||||||
- Abandoned cart
|
|
||||||
- Product recommendations
|
|
||||||
- Promotions and discounts
|
|
||||||
- Newsletter
|
|
||||||
|
|
||||||
**Operational (Low Priority):**
|
|
||||||
- Low stock alerts (for wishlisted items)
|
|
||||||
- Price drop alerts
|
|
||||||
- Back in stock alerts
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 Reusability Assessment
|
|
||||||
|
|
||||||
### Current Architecture Reusability
|
|
||||||
|
|
||||||
**✅ Highly Reusable:**
|
|
||||||
1. **NotificationManager.php** - Core logic
|
|
||||||
- `should_send_notification()` - Works for any recipient
|
|
||||||
- `send()` - Recipient-agnostic
|
|
||||||
|
|
||||||
2. **PushNotificationHandler.php** - Push infrastructure
|
|
||||||
- VAPID keys (shared)
|
|
||||||
- Subscription management (can be per-user)
|
|
||||||
- Sending logic (recipient-agnostic)
|
|
||||||
|
|
||||||
3. **ActivityLog** - Logging system
|
|
||||||
- Can log customer actions too
|
|
||||||
- Already tracks user_id
|
|
||||||
|
|
||||||
4. **Database Structure** - Settings storage
|
|
||||||
- `woonoow_notification_settings` - Can store customer event settings
|
|
||||||
- Just needs recipient field (already exists!)
|
|
||||||
|
|
||||||
**⚠️ Needs Adaptation:**
|
|
||||||
1. **Frontend UI** - Admin-only
|
|
||||||
- `admin-spa/` - Admin interface
|
|
||||||
- Need: `customer-spa/` interface
|
|
||||||
|
|
||||||
2. **REST API** - Permission checks
|
|
||||||
- Currently: `manage_woocommerce` permission
|
|
||||||
- Need: Customer-specific permissions
|
|
||||||
|
|
||||||
3. **Templates** - Admin-focused
|
|
||||||
- Need: Customer-facing templates
|
|
||||||
|
|
||||||
**❌ Not Reusable:**
|
|
||||||
1. **UI Components** - Admin design
|
|
||||||
- Need: Customer-facing design
|
|
||||||
- Different UX patterns
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 💡 Strategic Recommendations
|
|
||||||
|
|
||||||
### Option 1: Extend Current System (Recommended)
|
|
||||||
|
|
||||||
**Approach:** Add customer notifications to existing infrastructure
|
|
||||||
|
|
||||||
**Implementation:**
|
|
||||||
```
|
|
||||||
includes/Core/Notifications/
|
|
||||||
├── NotificationManager.php (already recipient-agnostic ✅)
|
|
||||||
├── PushNotificationHandler.php (already reusable ✅)
|
|
||||||
├── EmailHandler.php (new - handles both admin and customer)
|
|
||||||
└── TemplateEngine.php (new - shared templates)
|
|
||||||
|
|
||||||
admin-spa/src/routes/Settings/Notifications/
|
|
||||||
├── Staff/ (rename from current)
|
|
||||||
│ ├── Channels.tsx
|
|
||||||
│ ├── Events.tsx
|
|
||||||
│ └── Templates.tsx
|
|
||||||
└── Customer/ (new)
|
|
||||||
├── Channels.tsx (reuse component)
|
|
||||||
├── Events.tsx (reuse component)
|
|
||||||
└── Templates.tsx (reuse component)
|
|
||||||
|
|
||||||
customer-spa/src/routes/Account/Notifications/
|
|
||||||
└── Preferences.tsx (customer-facing preferences)
|
|
||||||
```
|
|
||||||
|
|
||||||
**Benefits:**
|
|
||||||
- ✅ Reuse 80% of backend code
|
|
||||||
- ✅ Reuse 60% of frontend components
|
|
||||||
- ✅ Consistent behavior
|
|
||||||
- ✅ Easier maintenance
|
|
||||||
|
|
||||||
**Effort:** 2-3 weeks
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Option 2: Separate Systems (Not Recommended)
|
|
||||||
|
|
||||||
**Approach:** Build separate customer notification system
|
|
||||||
|
|
||||||
**Problems:**
|
|
||||||
- ❌ Duplicate code
|
|
||||||
- ❌ Inconsistent behavior
|
|
||||||
- ❌ Double maintenance
|
|
||||||
- ❌ Wasted effort
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### Option 3: Hybrid Approach (Compromise)
|
|
||||||
|
|
||||||
**Approach:**
|
|
||||||
- Keep current system for admin
|
|
||||||
- Use WooCommerce emails for customers (for now)
|
|
||||||
- Add customer push notifications only
|
|
||||||
|
|
||||||
**Benefits:**
|
|
||||||
- ✅ Leverage WooCommerce's mature email system
|
|
||||||
- ✅ Focus on unique value (push notifications)
|
|
||||||
- ✅ Less effort
|
|
||||||
|
|
||||||
**Drawbacks:**
|
|
||||||
- ⚠️ Inconsistent UX
|
|
||||||
- ⚠️ Limited control over customer emails
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🏗️ Recommended Architecture
|
|
||||||
|
|
||||||
### Unified Notification System
|
|
||||||
|
|
||||||
```php
|
|
||||||
// Core (Recipient-agnostic)
|
|
||||||
NotificationManager
|
|
||||||
├── should_send_notification($event, $channel, $recipient)
|
|
||||||
├── get_recipients($event) // Returns ['admin', 'customer', 'both']
|
|
||||||
└── send($event, $channel, $recipient, $data)
|
|
||||||
|
|
||||||
// Channels (Recipient-agnostic)
|
|
||||||
EmailHandler
|
|
||||||
├── send_admin_email($event, $data)
|
|
||||||
└── send_customer_email($event, $data)
|
|
||||||
|
|
||||||
PushNotificationHandler
|
|
||||||
├── send_admin_push($event, $data)
|
|
||||||
└── send_customer_push($event, $data) // New
|
|
||||||
|
|
||||||
SMSHandler (Future)
|
|
||||||
├── send_admin_sms($event, $data)
|
|
||||||
└── send_customer_sms($event, $data)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Settings Structure
|
|
||||||
|
|
||||||
```php
|
|
||||||
// Unified settings
|
|
||||||
[
|
|
||||||
'staff_notifications' => [
|
|
||||||
'channels' => ['email' => true, 'push' => true],
|
|
||||||
'events' => [
|
|
||||||
'order_placed' => [
|
|
||||||
'channels' => ['email' => true, 'push' => true],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
'customer_notifications' => [
|
|
||||||
'channels' => ['email' => true, 'push' => false, 'sms' => false],
|
|
||||||
'events' => [
|
|
||||||
'order_placed' => [
|
|
||||||
'channels' => ['email' => true, 'push' => false],
|
|
||||||
'template' => 'order-confirmation',
|
|
||||||
],
|
|
||||||
],
|
|
||||||
],
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
### UI Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
Settings → Notifications
|
|
||||||
├── Staff Notifications (current)
|
|
||||||
│ ├── Channels (Email, Push)
|
|
||||||
│ ├── Events (Order, Product, Customer)
|
|
||||||
│ └── Templates
|
|
||||||
└── Customer Notifications (new)
|
|
||||||
├── Channels (Email, Push, SMS)
|
|
||||||
├── Events (Order, Account, Marketing)
|
|
||||||
└── Templates
|
|
||||||
|
|
||||||
Customer Account → Notification Preferences
|
|
||||||
├── Order Updates (Email ✓, Push ✗, SMS ✗)
|
|
||||||
├── Marketing (Email ✗, Push ✗, SMS ✗)
|
|
||||||
└── Account (Email ✓, Push ✗, SMS ✗)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📈 Impact Analysis
|
|
||||||
|
|
||||||
### Current System (Admin Only)
|
|
||||||
|
|
||||||
**Users Affected:** 1-5 admins per store
|
|
||||||
**Notifications/Day:** ~10-50
|
|
||||||
**Business Impact:** Faster response to orders, better inventory management
|
|
||||||
|
|
||||||
### With Customer Notifications
|
|
||||||
|
|
||||||
**Users Affected:** 100-10,000+ customers per store
|
|
||||||
**Notifications/Day:** ~100-1,000+
|
|
||||||
**Business Impact:**
|
|
||||||
- Better customer experience
|
|
||||||
- Reduced support tickets
|
|
||||||
- Higher customer satisfaction
|
|
||||||
- Increased repeat purchases
|
|
||||||
|
|
||||||
**ROI:** **10-100x higher impact**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 When to Build Customer Notifications?
|
|
||||||
|
|
||||||
### Timing Options
|
|
||||||
|
|
||||||
**Option A: Now (Recommended)**
|
|
||||||
- Reuse existing infrastructure
|
|
||||||
- Avoid technical debt
|
|
||||||
- Complete feature set
|
|
||||||
- Higher impact
|
|
||||||
|
|
||||||
**Option B: After Admin Stabilization**
|
|
||||||
- Polish admin features first
|
|
||||||
- Gather feedback
|
|
||||||
- Then extend to customers
|
|
||||||
- Risk: Harder to retrofit
|
|
||||||
|
|
||||||
**Option C: Separate Project**
|
|
||||||
- Treat as new feature
|
|
||||||
- Fresh start
|
|
||||||
- Risk: Duplicate code
|
|
||||||
|
|
||||||
**Recommendation:** **Option A - Build now while architecture is fresh**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔄 Migration Path
|
|
||||||
|
|
||||||
### Phase 1: Refactor Current System (1 week)
|
|
||||||
1. Rename `admin-spa/src/routes/Settings/Notifications/` → `Staff/`
|
|
||||||
2. Make backend recipient-agnostic
|
|
||||||
3. Add recipient field to all methods
|
|
||||||
4. Update database structure
|
|
||||||
|
|
||||||
### Phase 2: Add Customer Backend (1 week)
|
|
||||||
1. Customer notification events
|
|
||||||
2. Customer email templates
|
|
||||||
3. Customer push notification support
|
|
||||||
4. Customer preferences API
|
|
||||||
|
|
||||||
### Phase 3: Add Customer Frontend (1 week)
|
|
||||||
1. Admin UI: Customer Notifications section
|
|
||||||
2. Customer UI: Notification Preferences page
|
|
||||||
3. Reuse components from Staff section
|
|
||||||
4. Test and polish
|
|
||||||
|
|
||||||
**Total Effort:** 3 weeks
|
|
||||||
**Reuse Rate:** 70-80%
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📋 Comparison: Admin vs Customer Notifications
|
|
||||||
|
|
||||||
| Feature | Staff Notifications | Customer Notifications |
|
|
||||||
|---------|-------------------|----------------------|
|
|
||||||
| **Channels** | Email, Push | Email, Push, SMS (future) |
|
|
||||||
| **Events** | Orders, Products, Customers | Orders, Account, Marketing |
|
|
||||||
| **Templates** | Simple, functional | Rich, branded |
|
|
||||||
| **Frequency** | Low (10-50/day) | High (100-1000+/day) |
|
|
||||||
| **Recipients** | 1-5 admins | 100-10,000+ customers |
|
|
||||||
| **Priority** | High (business critical) | High (customer experience) |
|
|
||||||
| **Customization** | Admin controls | Customer controls (preferences) |
|
|
||||||
| **UI Location** | Admin dashboard | Customer account |
|
|
||||||
| **Permission** | Admin only | Customer only |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎨 UI/UX Recommendations
|
|
||||||
|
|
||||||
### Admin UI: Staff Notifications
|
|
||||||
|
|
||||||
**Current (Good):**
|
|
||||||
```
|
|
||||||
Settings → Notifications
|
|
||||||
├── Channels (Email, Push)
|
|
||||||
├── Events (Order, Product, Customer)
|
|
||||||
└── Templates
|
|
||||||
```
|
|
||||||
|
|
||||||
**Improved:**
|
|
||||||
```
|
|
||||||
Settings → Notifications → Staff
|
|
||||||
├── Channels (Email, Push)
|
|
||||||
├── Events (Order, Product, Customer)
|
|
||||||
├── Templates
|
|
||||||
└── Activity Log
|
|
||||||
```
|
|
||||||
|
|
||||||
### Admin UI: Customer Notifications (New)
|
|
||||||
|
|
||||||
```
|
|
||||||
Settings → Notifications → Customer
|
|
||||||
├── Channels
|
|
||||||
│ ├── Email (Enabled ✓)
|
|
||||||
│ ├── Push (Disabled ✗) - Requires customer opt-in
|
|
||||||
│ └── SMS (Addon) - Coming soon
|
|
||||||
├── Events
|
|
||||||
│ ├── Order Notifications
|
|
||||||
│ │ ├── Order Confirmation (Email ✓, Push ✗)
|
|
||||||
│ │ ├── Order Processing (Email ✓, Push ✗)
|
|
||||||
│ │ ├── Order Shipped (Email ✓, Push ✗)
|
|
||||||
│ │ └── Order Delivered (Email ✓, Push ✗)
|
|
||||||
│ ├── Account Notifications
|
|
||||||
│ │ ├── Welcome Email (Email ✓)
|
|
||||||
│ │ ├── Password Reset (Email ✓)
|
|
||||||
│ │ └── Account Verification (Email ✓)
|
|
||||||
│ └── Marketing (Optional)
|
|
||||||
│ ├── Abandoned Cart (Email ✗, Push ✗)
|
|
||||||
│ └── Promotions (Email ✗, Push ✗)
|
|
||||||
└── Templates
|
|
||||||
├── Order Confirmation Template
|
|
||||||
├── Shipping Update Template
|
|
||||||
└── Welcome Email Template
|
|
||||||
```
|
|
||||||
|
|
||||||
### Customer UI: Notification Preferences (New)
|
|
||||||
|
|
||||||
```
|
|
||||||
My Account → Notification Preferences
|
|
||||||
├── Order Updates
|
|
||||||
│ ├── Email notifications (✓ Enabled)
|
|
||||||
│ ├── Push notifications (✗ Disabled) - [Enable Push]
|
|
||||||
│ └── SMS notifications (✗ Disabled) - [Upgrade to enable]
|
|
||||||
├── Marketing
|
|
||||||
│ ├── Promotional emails (✗ Disabled)
|
|
||||||
│ ├── Product recommendations (✗ Disabled)
|
|
||||||
│ └── Newsletter (✗ Disabled)
|
|
||||||
└── Account
|
|
||||||
├── Security alerts (✓ Enabled - Cannot disable)
|
|
||||||
└── Account updates (✓ Enabled)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✅ Audit Conclusion
|
|
||||||
|
|
||||||
### Key Findings
|
|
||||||
|
|
||||||
1. **Current System is Admin-Only**
|
|
||||||
- Significant effort invested
|
|
||||||
- Limited user base (1-5 admins)
|
|
||||||
- Missing larger opportunity (customers)
|
|
||||||
|
|
||||||
2. **Architecture is 70-80% Reusable**
|
|
||||||
- Backend: Highly reusable
|
|
||||||
- Frontend: Components reusable, UI needs adaptation
|
|
||||||
- Database: Already supports recipients
|
|
||||||
|
|
||||||
3. **Industry Standard: Unified System**
|
|
||||||
- Shopify, BigCommerce: Separate UI, shared infrastructure
|
|
||||||
- WooCommerce: Mixed UI (poor UX)
|
|
||||||
- Best practice: Separate pages, shared components
|
|
||||||
|
|
||||||
4. **Customer Notifications = 10-100x Impact**
|
|
||||||
- More users
|
|
||||||
- More notifications
|
|
||||||
- Higher business value
|
|
||||||
- Better customer experience
|
|
||||||
|
|
||||||
### Recommendations
|
|
||||||
|
|
||||||
**1. Immediate Action: Refactor for Reusability**
|
|
||||||
- Rename current UI to "Staff Notifications"
|
|
||||||
- Make backend recipient-agnostic
|
|
||||||
- Prepare for customer notifications
|
|
||||||
|
|
||||||
**2. Short-term: Add Customer Notifications**
|
|
||||||
- Reuse 70-80% of code
|
|
||||||
- 3 weeks effort
|
|
||||||
- Complete feature set
|
|
||||||
|
|
||||||
**3. Long-term: Advanced Features**
|
|
||||||
- SMS notifications
|
|
||||||
- Marketing automation
|
|
||||||
- Advanced templates
|
|
||||||
- A/B testing
|
|
||||||
|
|
||||||
### Answer to Your Questions
|
|
||||||
|
|
||||||
**Q: Are these notification features only for admin?**
|
|
||||||
**A:** Yes, currently admin-only. This is a missed opportunity.
|
|
||||||
|
|
||||||
**Q: When is the right time to build it for customer?**
|
|
||||||
**A:** **Now.** While the architecture is fresh and before technical debt accumulates.
|
|
||||||
|
|
||||||
**Q: Can this feature be reused in customer-spa?**
|
|
||||||
**A:** **Yes, 70-80% reusable.** Backend is highly reusable, frontend components can be adapted.
|
|
||||||
|
|
||||||
**Q: How do modern stores handle customer notifications?**
|
|
||||||
**A:** Unified infrastructure, separate UIs. Shopify and BigCommerce use tabs/pages to separate staff and customer notifications.
|
|
||||||
|
|
||||||
**Q: What's the best UX?**
|
|
||||||
**A:** Separate pages (Staff Notifications, Customer Notifications) with shared components. Clear separation, consistent behavior.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚀 Next Steps
|
|
||||||
|
|
||||||
1. **Review this audit**
|
|
||||||
2. **Decide on approach:**
|
|
||||||
- Option A: Extend now (recommended)
|
|
||||||
- Option B: Extend later
|
|
||||||
- Option C: Keep admin-only
|
|
||||||
3. **If extending, follow migration path**
|
|
||||||
4. **Update documentation**
|
|
||||||
5. **Implement customer notifications**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Audit Status:** ✅ Complete
|
|
||||||
**Recommendation:** Extend to customer notifications now
|
|
||||||
**Expected ROI:** 10-100x higher impact
|
|
||||||
**Effort:** 3 weeks with 70-80% code reuse
|
|
||||||
@@ -1,481 +0,0 @@
|
|||||||
# Notification System Comparison: Industry Leaders
|
|
||||||
|
|
||||||
**Research Date:** November 11, 2025
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🏪 Shopify - Best Practice Example
|
|
||||||
|
|
||||||
### UI Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────────────────┐
|
|
||||||
│ Settings → Notifications │
|
|
||||||
├─────────────────────────────────────────────────────────┤
|
|
||||||
│ [Staff notifications] [Customer notifications] │
|
|
||||||
├─────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ STAFF NOTIFICATIONS │
|
|
||||||
│ │
|
|
||||||
│ Orders │
|
|
||||||
│ ├─ New order [Email ✓] [Push ✓]│
|
|
||||||
│ ├─ Order cancelled [Email ✓] [Push ✗]│
|
|
||||||
│ └─ Order refunded [Email ✓] [Push ✗]│
|
|
||||||
│ │
|
|
||||||
│ Products │
|
|
||||||
│ ├─ Low stock [Email ✓] [Push ✓]│
|
|
||||||
│ └─ Out of stock [Email ✓] [Push ✓]│
|
|
||||||
│ │
|
|
||||||
│ Customers │
|
|
||||||
│ └─ New customer [Email ✓] [Push ✗]│
|
|
||||||
│ │
|
|
||||||
└─────────────────────────────────────────────────────────┘
|
|
||||||
|
|
||||||
┌─────────────────────────────────────────────────────────┐
|
|
||||||
│ Settings → Notifications │
|
|
||||||
├─────────────────────────────────────────────────────────┤
|
|
||||||
│ [Staff notifications] [Customer notifications] │
|
|
||||||
├─────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ CUSTOMER NOTIFICATIONS │
|
|
||||||
│ │
|
|
||||||
│ Order notifications │
|
|
||||||
│ ├─ Order confirmation [Email ✓] [SMS ✗] │
|
|
||||||
│ ├─ Order in transit [Email ✓] [SMS ✗] │
|
|
||||||
│ ├─ Out for delivery [Email ✓] [SMS ✓] │
|
|
||||||
│ └─ Delivered [Email ✓] [SMS ✗] │
|
|
||||||
│ │
|
|
||||||
│ Shipping notifications │
|
|
||||||
│ ├─ Shipping confirmation [Email ✓] [SMS ✗] │
|
|
||||||
│ └─ Shipping update [Email ✓] [SMS ✗] │
|
|
||||||
│ │
|
|
||||||
│ Customer account │
|
|
||||||
│ ├─ Welcome email [Email ✓] │
|
|
||||||
│ ├─ Account activation [Email ✓] │
|
|
||||||
│ └─ Password reset [Email ✓] │
|
|
||||||
│ │
|
|
||||||
└─────────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
**Key Features:**
|
|
||||||
- ✅ Clear separation (tabs)
|
|
||||||
- ✅ Same UI pattern for both
|
|
||||||
- ✅ Channel toggles per event
|
|
||||||
- ✅ Email + SMS for customers
|
|
||||||
- ✅ Email + Push for staff
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🛒 WooCommerce - Current (Poor UX)
|
|
||||||
|
|
||||||
### UI Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────────────────┐
|
|
||||||
│ WooCommerce → Settings → Emails │
|
|
||||||
├─────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ Email notifications │
|
|
||||||
│ │
|
|
||||||
│ ┌──────────────────────────────────────────────────┐ │
|
|
||||||
│ │ New order [Admin] │ │
|
|
||||||
│ │ Sent to admins when a new order is received │ │
|
|
||||||
│ │ [Enabled ✓] [Manage] │ │
|
|
||||||
│ └──────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ ┌──────────────────────────────────────────────────┐ │
|
|
||||||
│ │ Cancelled order [Admin] │ │
|
|
||||||
│ │ Sent to admins when an order is cancelled │ │
|
|
||||||
│ │ [Enabled ✓] [Manage] │ │
|
|
||||||
│ └──────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ ┌──────────────────────────────────────────────────┐ │
|
|
||||||
│ │ Processing order [Customer] │ │
|
|
||||||
│ │ Sent to customers when order is processing │ │
|
|
||||||
│ │ [Enabled ✓] [Manage] │ │
|
|
||||||
│ └──────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ ┌──────────────────────────────────────────────────┐ │
|
|
||||||
│ │ Completed order [Customer] │ │
|
|
||||||
│ │ Sent to customers when order is completed │ │
|
|
||||||
│ │ [Enabled ✓] [Manage] │ │
|
|
||||||
│ └──────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ ┌──────────────────────────────────────────────────┐ │
|
|
||||||
│ │ Customer note [Customer] │ │
|
|
||||||
│ │ Sent to customers when a note is added │ │
|
|
||||||
│ │ [Enabled ✓] [Manage] │ │
|
|
||||||
│ └──────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
└─────────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
**Problems:**
|
|
||||||
- ❌ Admin and customer emails mixed
|
|
||||||
- ❌ Hard to find specific email
|
|
||||||
- ❌ No clear grouping
|
|
||||||
- ❌ Email only (no push, no SMS)
|
|
||||||
- ❌ Poor visual hierarchy
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🏢 BigCommerce - Good Separation
|
|
||||||
|
|
||||||
### UI Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────────────────┐
|
|
||||||
│ Settings → Email Notifications │
|
|
||||||
├─────────────────────────────────────────────────────────┤
|
|
||||||
│ [Staff] [Customer] │
|
|
||||||
├─────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ STAFF EMAIL NOTIFICATIONS │
|
|
||||||
│ │
|
|
||||||
│ Order notifications │
|
|
||||||
│ ┌────────────────────────────────────────────────┐ │
|
|
||||||
│ │ ☑ New order received │ │
|
|
||||||
│ │ Send email when a new order is placed │ │
|
|
||||||
│ │ Recipients: admin@store.com │ │
|
|
||||||
│ └────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ ┌────────────────────────────────────────────────┐ │
|
|
||||||
│ │ ☑ Low stock alert │ │
|
|
||||||
│ │ Send email when product stock is low │ │
|
|
||||||
│ │ Recipients: admin@store.com │ │
|
|
||||||
│ │ Threshold: 5 items │ │
|
|
||||||
│ └────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
└─────────────────────────────────────────────────────────┘
|
|
||||||
|
|
||||||
┌─────────────────────────────────────────────────────────┐
|
|
||||||
│ Settings → Email Notifications │
|
|
||||||
├─────────────────────────────────────────────────────────┤
|
|
||||||
│ [Staff] [Customer] │
|
|
||||||
├─────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ CUSTOMER EMAIL NOTIFICATIONS │
|
|
||||||
│ │
|
|
||||||
│ Order status emails │
|
|
||||||
│ ┌────────────────────────────────────────────────┐ │
|
|
||||||
│ │ ☑ Order confirmation │ │
|
|
||||||
│ │ Sent when order is placed │ │
|
|
||||||
│ │ [Edit template] │ │
|
|
||||||
│ └────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ ┌────────────────────────────────────────────────┐ │
|
|
||||||
│ │ ☑ Order shipped │ │
|
|
||||||
│ │ Sent when order is shipped │ │
|
|
||||||
│ │ Include tracking: ☑ Yes │ │
|
|
||||||
│ │ [Edit template] │ │
|
|
||||||
│ └────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ Account emails │
|
|
||||||
│ ┌────────────────────────────────────────────────┐ │
|
|
||||||
│ │ ☑ Welcome email │ │
|
|
||||||
│ │ Sent when customer creates account │ │
|
|
||||||
│ │ [Edit template] │ │
|
|
||||||
│ └────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
└─────────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
**Key Features:**
|
|
||||||
- ✅ Clear tab separation
|
|
||||||
- ✅ Grouped by category
|
|
||||||
- ✅ Inline settings (recipients, threshold)
|
|
||||||
- ✅ Template editing
|
|
||||||
- ✅ Good visual hierarchy
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 💳 Stripe - Developer-Friendly
|
|
||||||
|
|
||||||
### UI Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────────────────┐
|
|
||||||
│ Settings → Notifications │
|
|
||||||
├─────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ Email notifications │
|
|
||||||
│ │
|
|
||||||
│ Business notifications │
|
|
||||||
│ ☑ Successful payments │
|
|
||||||
│ ☑ Failed payments │
|
|
||||||
│ ☑ Disputes │
|
|
||||||
│ ☑ Payouts │
|
|
||||||
│ │
|
|
||||||
│ Recipients: admin@business.com [Add] │
|
|
||||||
│ │
|
|
||||||
│ ───────────────────────────────────────────────────── │
|
|
||||||
│ │
|
|
||||||
│ Customer emails │
|
|
||||||
│ ☑ Successful payments │
|
|
||||||
│ ☑ Refunds │
|
|
||||||
│ ☑ Invoices │
|
|
||||||
│ │
|
|
||||||
│ [Customize email templates] │
|
|
||||||
│ │
|
|
||||||
│ ───────────────────────────────────────────────────── │
|
|
||||||
│ │
|
|
||||||
│ Webhooks │
|
|
||||||
│ Send real-time notifications to your server │
|
|
||||||
│ │
|
|
||||||
│ Endpoint URL: https://api.example.com/webhooks │
|
|
||||||
│ Events: payment_intent.succeeded, charge.failed, ... │
|
|
||||||
│ │
|
|
||||||
│ [Add endpoint] │
|
|
||||||
│ │
|
|
||||||
└─────────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
**Key Features:**
|
|
||||||
- ✅ Simple, clean layout
|
|
||||||
- ✅ Business vs Customer separation
|
|
||||||
- ✅ Webhook support (developer)
|
|
||||||
- ✅ Template customization
|
|
||||||
- ✅ Recipient management
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📱 Customer-Facing Preferences (Shopify Mobile App)
|
|
||||||
|
|
||||||
### UI Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────────────────┐
|
|
||||||
│ Account → Notification Preferences │
|
|
||||||
├─────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ Order updates │
|
|
||||||
│ Get notified about your order status │
|
|
||||||
│ │
|
|
||||||
│ ┌────────────────────────────────────────────────┐ │
|
|
||||||
│ │ Email [●──────] Enabled │ │
|
|
||||||
│ │ Push notifications [──────○] Disabled │ │
|
|
||||||
│ │ SMS [──────○] Disabled │ │
|
|
||||||
│ └────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ Marketing │
|
|
||||||
│ Promotions, new products, and special offers │
|
|
||||||
│ │
|
|
||||||
│ ┌────────────────────────────────────────────────┐ │
|
|
||||||
│ │ Email [──────○] Disabled │ │
|
|
||||||
│ │ Push notifications [──────○] Disabled │ │
|
|
||||||
│ │ SMS [──────○] Disabled │ │
|
|
||||||
│ └────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ Account │
|
|
||||||
│ Security alerts and account updates │
|
|
||||||
│ │
|
|
||||||
│ ┌────────────────────────────────────────────────┐ │
|
|
||||||
│ │ Email [●──────] Enabled (Required) │ │
|
|
||||||
│ │ Push notifications [──────○] Disabled │ │
|
|
||||||
│ └────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ [Save preferences] │
|
|
||||||
│ │
|
|
||||||
└─────────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
**Key Features:**
|
|
||||||
- ✅ Customer controls their preferences
|
|
||||||
- ✅ Clear categories
|
|
||||||
- ✅ Multiple channels per category
|
|
||||||
- ✅ Visual toggles
|
|
||||||
- ✅ Required notifications marked
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 Recommended Structure for WooNooW
|
|
||||||
|
|
||||||
### Admin UI: Settings → Notifications
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────────────────┐
|
|
||||||
│ Settings → Notifications │
|
|
||||||
├─────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ ┌─────────────────┐ ┌─────────────────┐ │
|
|
||||||
│ │ Staff │ │ Customer │ │
|
|
||||||
│ │ Notifications │ │ Notifications │ │
|
|
||||||
│ │ │ │ │ │
|
|
||||||
│ │ Get alerts for │ │ Manage customer │ │
|
|
||||||
│ │ orders, stock, │ │ email and push │ │
|
|
||||||
│ │ and more │ │ notifications │ │
|
|
||||||
│ │ │ │ │ │
|
|
||||||
│ │ [Configure →] │ │ [Configure →] │ │
|
|
||||||
│ └─────────────────┘ └─────────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ ┌─────────────────┐ ┌─────────────────┐ │
|
|
||||||
│ │ Activity Log │ │ Templates │ │
|
|
||||||
│ │ │ │ │ │
|
|
||||||
│ │ View all │ │ Customize email │ │
|
|
||||||
│ │ notification │ │ and push │ │
|
|
||||||
│ │ activities │ │ templates │ │
|
|
||||||
│ │ │ │ │ │
|
|
||||||
│ │ [View log →] │ │ [Manage →] │ │
|
|
||||||
│ └─────────────────┘ └─────────────────┘ │
|
|
||||||
│ │
|
|
||||||
└─────────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
### Admin UI: Staff Notifications
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────────────────┐
|
|
||||||
│ Settings → Notifications → Staff │
|
|
||||||
├─────────────────────────────────────────────────────────┤
|
|
||||||
│ ← Back to Notifications │
|
|
||||||
│ │
|
|
||||||
│ [Channels] [Events] [Templates] │
|
|
||||||
├─────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ CHANNELS │
|
|
||||||
│ │
|
|
||||||
│ ┌────────────────────────────────────────────────┐ │
|
|
||||||
│ │ 📧 Email [●──] Enabled│ │
|
|
||||||
│ │ Email notifications powered by WordPress │ │
|
|
||||||
│ │ Recipients: admin@store.com [Edit] │ │
|
|
||||||
│ │ [Configure] │ │
|
|
||||||
│ └────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ ┌────────────────────────────────────────────────┐ │
|
|
||||||
│ │ 🔔 Push Notifications [──○] Disabled│ │
|
|
||||||
│ │ Browser push notifications │ │
|
|
||||||
│ │ [Enable and subscribe] │ │
|
|
||||||
│ └────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
└─────────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
### Admin UI: Customer Notifications (NEW)
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────────────────┐
|
|
||||||
│ Settings → Notifications → Customer │
|
|
||||||
├─────────────────────────────────────────────────────────┤
|
|
||||||
│ ← Back to Notifications │
|
|
||||||
│ │
|
|
||||||
│ [Channels] [Events] [Templates] │
|
|
||||||
├─────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ CHANNELS │
|
|
||||||
│ │
|
|
||||||
│ ┌────────────────────────────────────────────────┐ │
|
|
||||||
│ │ 📧 Email [●──] Enabled│ │
|
|
||||||
│ │ Transactional emails to customers │ │
|
|
||||||
│ │ From: store@example.com [Edit] │ │
|
|
||||||
│ │ [Configure] │ │
|
|
||||||
│ └────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ ┌────────────────────────────────────────────────┐ │
|
|
||||||
│ │ 🔔 Push Notifications [──○] Disabled│ │
|
|
||||||
│ │ Browser push (requires customer opt-in) │ │
|
|
||||||
│ │ [Enable] │ │
|
|
||||||
│ └────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ ┌────────────────────────────────────────────────┐ │
|
|
||||||
│ │ 📱 SMS Notifications [──○] Disabled│ │
|
|
||||||
│ │ Text messages (addon required) │ │
|
|
||||||
│ │ [Install SMS addon] │ │
|
|
||||||
│ └────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
└─────────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
### Customer UI: My Account → Notifications (NEW)
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────────────────────┐
|
|
||||||
│ My Account → Notification Preferences │
|
|
||||||
├─────────────────────────────────────────────────────────┤
|
|
||||||
│ │
|
|
||||||
│ Manage how you receive notifications │
|
|
||||||
│ │
|
|
||||||
│ ┌────────────────────────────────────────────────┐ │
|
|
||||||
│ │ 📦 Order Updates │ │
|
|
||||||
│ │ Get notified about your order status │ │
|
|
||||||
│ │ │ │
|
|
||||||
│ │ Email [●──────] Enabled │ │
|
|
||||||
│ │ Push notifications [──────○] Disabled │ │
|
|
||||||
│ │ [Enable push] │ │
|
|
||||||
│ └────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ ┌────────────────────────────────────────────────┐ │
|
|
||||||
│ │ 🎁 Marketing & Promotions │ │
|
|
||||||
│ │ Special offers and new products │ │
|
|
||||||
│ │ │ │
|
|
||||||
│ │ Email [──────○] Disabled │ │
|
|
||||||
│ │ Push notifications [──────○] Disabled │ │
|
|
||||||
│ └────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ ┌────────────────────────────────────────────────┐ │
|
|
||||||
│ │ 🔐 Account & Security │ │
|
|
||||||
│ │ Important account updates (required) │ │
|
|
||||||
│ │ │ │
|
|
||||||
│ │ Email [●──────] Enabled │ │
|
|
||||||
│ │ (Cannot be disabled) │ │
|
|
||||||
│ └────────────────────────────────────────────────┘ │
|
|
||||||
│ │
|
|
||||||
│ [Save preferences] │
|
|
||||||
│ │
|
|
||||||
└─────────────────────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📊 Comparison Summary
|
|
||||||
|
|
||||||
| Platform | Separation | Channels | Customer Control | UX Rating |
|
|
||||||
|----------|-----------|----------|-----------------|-----------|
|
|
||||||
| **Shopify** | ✅ Tabs | Email, Push, SMS | ✅ Yes | ⭐⭐⭐⭐⭐ |
|
|
||||||
| **BigCommerce** | ✅ Tabs | Email | ✅ Yes | ⭐⭐⭐⭐ |
|
|
||||||
| **WooCommerce** | ❌ Mixed | Email only | ❌ No | ⭐⭐ |
|
|
||||||
| **Stripe** | ✅ Sections | Email, Webhooks | ✅ Yes | ⭐⭐⭐⭐ |
|
|
||||||
| **WooNooW (Current)** | N/A (Admin only) | Email, Push | N/A | ⭐⭐⭐ |
|
|
||||||
| **WooNooW (Proposed)** | ✅ Pages | Email, Push, SMS | ✅ Yes | ⭐⭐⭐⭐⭐ |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 Key Takeaways
|
|
||||||
|
|
||||||
1. **Industry Standard: Separate UIs**
|
|
||||||
- Staff and customer notifications are separate
|
|
||||||
- Same infrastructure, different interfaces
|
|
||||||
- Clear visual separation (tabs or pages)
|
|
||||||
|
|
||||||
2. **Customer Control is Essential**
|
|
||||||
- Customers must control their preferences
|
|
||||||
- Multiple channels per category
|
|
||||||
- Some notifications are required (security)
|
|
||||||
|
|
||||||
3. **Channel Flexibility**
|
|
||||||
- Email is baseline (always available)
|
|
||||||
- Push requires opt-in
|
|
||||||
- SMS is premium/addon
|
|
||||||
|
|
||||||
4. **Template Management**
|
|
||||||
- Shared templates between staff and customer
|
|
||||||
- Different styling/branding
|
|
||||||
- Easy customization
|
|
||||||
|
|
||||||
5. **WooCommerce is Behind**
|
|
||||||
- Poor UX (mixed admin/customer)
|
|
||||||
- Email only
|
|
||||||
- No customer control
|
|
||||||
- **Opportunity for WooNooW to excel!**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✅ Recommendation
|
|
||||||
|
|
||||||
**Implement the proposed structure:**
|
|
||||||
- Separate Staff and Customer notification pages
|
|
||||||
- Reuse 70-80% of existing code
|
|
||||||
- Add customer-facing preferences page
|
|
||||||
- Support Email, Push, and SMS (future)
|
|
||||||
- Follow Shopify/BigCommerce best practices
|
|
||||||
|
|
||||||
**Result:** Best-in-class notification system for WooCommerce! 🚀
|
|
||||||
@@ -1,428 +0,0 @@
|
|||||||
# Notification System Enhancements - Implementation Plan
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
This document outlines the complete implementation plan for notification system enhancements, including dynamic URLs, activity logging, and customer notifications.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 1. Customer Email Notifications
|
|
||||||
|
|
||||||
### Current State
|
|
||||||
- WooCommerce handles customer emails automatically
|
|
||||||
- WooNooW notifications are for admin alerts only
|
|
||||||
- Recipient field exists but not fully utilized
|
|
||||||
|
|
||||||
### Strategy: Integration, Not Replacement
|
|
||||||
|
|
||||||
**Decision:** Keep WooCommerce's customer email system, add admin notification layer
|
|
||||||
|
|
||||||
**Why:**
|
|
||||||
- ✅ WooCommerce emails are battle-tested
|
|
||||||
- ✅ Merchants already customize them
|
|
||||||
- ✅ Templates, styling, and logic already exist
|
|
||||||
- ✅ We focus on admin experience
|
|
||||||
|
|
||||||
**What We Add:**
|
|
||||||
- Admin notifications (email + push)
|
|
||||||
- Real-time alerts for admins
|
|
||||||
- Activity logging
|
|
||||||
- Better UI for managing notifications
|
|
||||||
|
|
||||||
### Implementation
|
|
||||||
|
|
||||||
**No code changes needed!** System already supports:
|
|
||||||
- `recipient: 'admin'` - Admin notifications
|
|
||||||
- `recipient: 'customer'` - Customer notifications (via WooCommerce)
|
|
||||||
- `recipient: 'both'` - Both (admin via WooNooW, customer via WooCommerce)
|
|
||||||
|
|
||||||
**Documentation Update:**
|
|
||||||
- Clarify that customer emails use WooCommerce
|
|
||||||
- Document integration points
|
|
||||||
- Add filter for custom recipient logic
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 2. Activity Log System
|
|
||||||
|
|
||||||
### Current State
|
|
||||||
- WooCommerce has order notes (limited)
|
|
||||||
- No comprehensive activity log
|
|
||||||
- No UI for viewing all activities
|
|
||||||
|
|
||||||
### Strategy: Build Custom Activity Log
|
|
||||||
|
|
||||||
**Why Build Our Own:**
|
|
||||||
- ✅ Full control over what's logged
|
|
||||||
- ✅ Better UI/UX
|
|
||||||
- ✅ Searchable and filterable
|
|
||||||
- ✅ Integration with notifications
|
|
||||||
- ✅ Real-time updates
|
|
||||||
|
|
||||||
### Data Structure
|
|
||||||
|
|
||||||
```php
|
|
||||||
// wp_woonoow_activity_log table
|
|
||||||
CREATE TABLE wp_woonoow_activity_log (
|
|
||||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
|
||||||
user_id BIGINT UNSIGNED NOT NULL,
|
|
||||||
action VARCHAR(50) NOT NULL,
|
|
||||||
object_type VARCHAR(50) NOT NULL,
|
|
||||||
object_id BIGINT UNSIGNED NOT NULL,
|
|
||||||
description TEXT,
|
|
||||||
metadata LONGTEXT, -- JSON
|
|
||||||
ip_address VARCHAR(45),
|
|
||||||
user_agent TEXT,
|
|
||||||
created_at DATETIME NOT NULL,
|
|
||||||
INDEX idx_user_id (user_id),
|
|
||||||
INDEX idx_action (action),
|
|
||||||
INDEX idx_object (object_type, object_id),
|
|
||||||
INDEX idx_created_at (created_at)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
||||||
```
|
|
||||||
|
|
||||||
### Activity Types
|
|
||||||
|
|
||||||
**Orders:**
|
|
||||||
- `order.created` - Order created
|
|
||||||
- `order.updated` - Order updated
|
|
||||||
- `order.status_changed` - Status changed
|
|
||||||
- `order.payment_completed` - Payment completed
|
|
||||||
- `order.refunded` - Order refunded
|
|
||||||
- `order.deleted` - Order deleted
|
|
||||||
|
|
||||||
**Products:**
|
|
||||||
- `product.created` - Product created
|
|
||||||
- `product.updated` - Product updated
|
|
||||||
- `product.stock_changed` - Stock changed
|
|
||||||
- `product.deleted` - Product deleted
|
|
||||||
|
|
||||||
**Customers:**
|
|
||||||
- `customer.created` - Customer registered
|
|
||||||
- `customer.updated` - Customer updated
|
|
||||||
- `customer.deleted` - Customer deleted
|
|
||||||
|
|
||||||
**Notifications:**
|
|
||||||
- `notification.sent` - Notification sent
|
|
||||||
- `notification.failed` - Notification failed
|
|
||||||
- `notification.clicked` - Notification clicked
|
|
||||||
|
|
||||||
**Settings:**
|
|
||||||
- `settings.updated` - Settings changed
|
|
||||||
- `channel.toggled` - Channel enabled/disabled
|
|
||||||
- `event.toggled` - Event enabled/disabled
|
|
||||||
|
|
||||||
### Implementation Files
|
|
||||||
|
|
||||||
**Backend:**
|
|
||||||
1. `includes/Core/ActivityLog/Logger.php` - Main logger class
|
|
||||||
2. `includes/Core/ActivityLog/ActivityLogTable.php` - Database table
|
|
||||||
3. `includes/Api/ActivityLogController.php` - REST API
|
|
||||||
4. Hook into WooCommerce actions
|
|
||||||
|
|
||||||
**Frontend:**
|
|
||||||
1. `admin-spa/src/routes/ActivityLog/index.tsx` - Activity log page
|
|
||||||
2. `admin-spa/src/routes/ActivityLog/ActivityItem.tsx` - Single activity
|
|
||||||
3. `admin-spa/src/routes/ActivityLog/Filters.tsx` - Filter UI
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 3. Dynamic Push Notification URLs
|
|
||||||
|
|
||||||
### Current State
|
|
||||||
- Global URL: `/wp-admin/admin.php?page=woonoow#/orders`
|
|
||||||
- All notifications go to same page
|
|
||||||
|
|
||||||
### Strategy: Event-Specific Deep Links
|
|
||||||
|
|
||||||
### URL Templates
|
|
||||||
|
|
||||||
```php
|
|
||||||
$url_templates = [
|
|
||||||
// Orders
|
|
||||||
'order_placed' => '/wp-admin/admin.php?page=woonoow#/orders/{order_id}',
|
|
||||||
'order_processing' => '/wp-admin/admin.php?page=woonoow#/orders/{order_id}',
|
|
||||||
'order_completed' => '/wp-admin/admin.php?page=woonoow#/orders/{order_id}',
|
|
||||||
'order_cancelled' => '/wp-admin/admin.php?page=woonoow#/orders/{order_id}',
|
|
||||||
'order_refunded' => '/wp-admin/admin.php?page=woonoow#/orders/{order_id}',
|
|
||||||
|
|
||||||
// Products
|
|
||||||
'low_stock' => '/wp-admin/admin.php?page=woonoow#/products/{product_id}',
|
|
||||||
'out_of_stock' => '/wp-admin/admin.php?page=woonoow#/products/{product_id}',
|
|
||||||
|
|
||||||
// Customers
|
|
||||||
'new_customer' => '/wp-admin/admin.php?page=woonoow#/customers/{customer_id}',
|
|
||||||
'customer_note' => '/wp-admin/admin.php?page=woonoow#/orders/{order_id}',
|
|
||||||
];
|
|
||||||
```
|
|
||||||
|
|
||||||
### Template Variables
|
|
||||||
|
|
||||||
**Available Variables:**
|
|
||||||
- `{order_id}` - Order ID
|
|
||||||
- `{product_id}` - Product ID
|
|
||||||
- `{customer_id}` - Customer ID
|
|
||||||
- `{user_id}` - User ID
|
|
||||||
- `{site_url}` - Site URL
|
|
||||||
- `{admin_url}` - Admin URL
|
|
||||||
|
|
||||||
### Implementation
|
|
||||||
|
|
||||||
**Backend:**
|
|
||||||
1. Add URL template field to push settings
|
|
||||||
2. Parse template variables when sending
|
|
||||||
3. Store parsed URL in notification metadata
|
|
||||||
|
|
||||||
**Frontend:**
|
|
||||||
1. Add URL template field to Templates page
|
|
||||||
2. Show available variables
|
|
||||||
3. Preview parsed URL
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 4. Rich Notification Content
|
|
||||||
|
|
||||||
### Event-Specific Icons
|
|
||||||
|
|
||||||
```php
|
|
||||||
$notification_icons = [
|
|
||||||
'order_placed' => '🛒',
|
|
||||||
'order_processing' => '⚙️',
|
|
||||||
'order_completed' => '✅',
|
|
||||||
'order_cancelled' => '❌',
|
|
||||||
'order_refunded' => '💰',
|
|
||||||
'low_stock' => '📦',
|
|
||||||
'out_of_stock' => '🚫',
|
|
||||||
'new_customer' => '👤',
|
|
||||||
'customer_note' => '💬',
|
|
||||||
];
|
|
||||||
```
|
|
||||||
|
|
||||||
### Event-Specific Images
|
|
||||||
|
|
||||||
**Order Notifications:**
|
|
||||||
- Show first product image
|
|
||||||
- Fallback to store logo
|
|
||||||
|
|
||||||
**Product Notifications:**
|
|
||||||
- Show product image
|
|
||||||
- Fallback to placeholder
|
|
||||||
|
|
||||||
**Customer Notifications:**
|
|
||||||
- Show customer avatar (Gravatar)
|
|
||||||
- Fallback to default avatar
|
|
||||||
|
|
||||||
### Rich Content Structure
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"title": "New Order #1234",
|
|
||||||
"body": "John Doe ordered 2 items (Rp137.000)",
|
|
||||||
"icon": "🛒",
|
|
||||||
"image": "https://example.com/product.jpg",
|
|
||||||
"badge": "https://example.com/logo.png",
|
|
||||||
"data": {
|
|
||||||
"url": "/wp-admin/admin.php?page=woonoow#/orders/1234",
|
|
||||||
"order_id": 1234,
|
|
||||||
"customer_name": "John Doe",
|
|
||||||
"total": 137000
|
|
||||||
},
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"action": "view",
|
|
||||||
"title": "View Order",
|
|
||||||
"icon": "👁️"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"action": "mark_processing",
|
|
||||||
"title": "Mark Processing",
|
|
||||||
"icon": "⚙️"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Implementation Priority
|
|
||||||
|
|
||||||
### Phase 1: Dynamic URLs (Immediate) ✅
|
|
||||||
1. Add URL template to push settings
|
|
||||||
2. Parse template variables
|
|
||||||
3. Update notification sending logic
|
|
||||||
4. Test with different events
|
|
||||||
|
|
||||||
### Phase 2: Activity Log (Immediate) ✅
|
|
||||||
1. Create database table
|
|
||||||
2. Implement Logger class
|
|
||||||
3. Hook into WooCommerce actions
|
|
||||||
4. Create REST API
|
|
||||||
5. Build frontend UI
|
|
||||||
|
|
||||||
### Phase 3: Rich Content (Future) 📋
|
|
||||||
1. Add icon field to events
|
|
||||||
2. Add image field to events
|
|
||||||
3. Implement image fetching logic
|
|
||||||
4. Update push notification payload
|
|
||||||
5. Test on different browsers
|
|
||||||
|
|
||||||
### Phase 4: Notification Actions (Future) 📋
|
|
||||||
1. Define action types
|
|
||||||
2. Implement action handlers
|
|
||||||
3. Update push notification payload
|
|
||||||
4. Handle action clicks
|
|
||||||
5. Test on different browsers
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Database Schema
|
|
||||||
|
|
||||||
### Activity Log Table
|
|
||||||
|
|
||||||
```sql
|
|
||||||
CREATE TABLE IF NOT EXISTS wp_woonoow_activity_log (
|
|
||||||
id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
|
|
||||||
user_id BIGINT UNSIGNED NOT NULL,
|
|
||||||
user_name VARCHAR(255) NOT NULL,
|
|
||||||
action VARCHAR(50) NOT NULL,
|
|
||||||
object_type VARCHAR(50) NOT NULL,
|
|
||||||
object_id BIGINT UNSIGNED NOT NULL,
|
|
||||||
object_name VARCHAR(255),
|
|
||||||
description TEXT,
|
|
||||||
metadata LONGTEXT,
|
|
||||||
ip_address VARCHAR(45),
|
|
||||||
user_agent TEXT,
|
|
||||||
created_at DATETIME NOT NULL,
|
|
||||||
|
|
||||||
INDEX idx_user_id (user_id),
|
|
||||||
INDEX idx_action (action),
|
|
||||||
INDEX idx_object (object_type, object_id),
|
|
||||||
INDEX idx_created_at (created_at)
|
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
|
||||||
```
|
|
||||||
|
|
||||||
### Push Settings Update
|
|
||||||
|
|
||||||
```php
|
|
||||||
// Add to woonoow_push_notification_settings
|
|
||||||
[
|
|
||||||
'enabled' => true,
|
|
||||||
'vapid_public_key' => '...',
|
|
||||||
'vapid_private_key' => '...',
|
|
||||||
'default_url' => '/wp-admin/admin.php?page=woonoow#/orders',
|
|
||||||
'url_templates' => [
|
|
||||||
'order_placed' => '/wp-admin/admin.php?page=woonoow#/orders/{order_id}',
|
|
||||||
// ... more templates
|
|
||||||
],
|
|
||||||
'show_store_logo' => true,
|
|
||||||
'show_product_images' => true,
|
|
||||||
'show_customer_avatar' => true,
|
|
||||||
'require_interaction' => false,
|
|
||||||
'silent_notifications' => false,
|
|
||||||
]
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## API Endpoints
|
|
||||||
|
|
||||||
### Activity Log
|
|
||||||
|
|
||||||
```
|
|
||||||
GET /woonoow/v1/activity-log
|
|
||||||
?page=1&per_page=20&action=order.created&user_id=1&date_from=2025-11-01
|
|
||||||
|
|
||||||
POST /woonoow/v1/activity-log
|
|
||||||
{ action, object_type, object_id, description, metadata }
|
|
||||||
|
|
||||||
GET /woonoow/v1/activity-log/stats
|
|
||||||
?date_from=2025-11-01&date_to=2025-11-30
|
|
||||||
```
|
|
||||||
|
|
||||||
### Push Notification URLs
|
|
||||||
|
|
||||||
```
|
|
||||||
GET /woonoow/v1/notifications/push/url-templates
|
|
||||||
|
|
||||||
POST /woonoow/v1/notifications/push/url-templates
|
|
||||||
{ event_id, url_template }
|
|
||||||
|
|
||||||
POST /woonoow/v1/notifications/push/preview-url
|
|
||||||
{ event_id, url_template, variables }
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Testing Checklist
|
|
||||||
|
|
||||||
### Dynamic URLs
|
|
||||||
- [ ] Order notification → Order detail page
|
|
||||||
- [ ] Product notification → Product edit page
|
|
||||||
- [ ] Customer notification → Customer page
|
|
||||||
- [ ] Variables parsed correctly
|
|
||||||
- [ ] Fallback to default URL
|
|
||||||
|
|
||||||
### Activity Log
|
|
||||||
- [ ] Activities logged correctly
|
|
||||||
- [ ] Filtering works
|
|
||||||
- [ ] Pagination works
|
|
||||||
- [ ] Search works
|
|
||||||
- [ ] Real-time updates
|
|
||||||
- [ ] Performance with 10k+ logs
|
|
||||||
|
|
||||||
### Rich Content
|
|
||||||
- [ ] Icons display correctly
|
|
||||||
- [ ] Images load correctly
|
|
||||||
- [ ] Fallbacks work
|
|
||||||
- [ ] Different browsers (Chrome, Firefox, Safari)
|
|
||||||
- [ ] Mobile devices
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Success Metrics
|
|
||||||
|
|
||||||
**User Experience:**
|
|
||||||
- Click-through rate on notifications
|
|
||||||
- Time to action after notification
|
|
||||||
- User satisfaction score
|
|
||||||
|
|
||||||
**Technical:**
|
|
||||||
- Notification delivery rate
|
|
||||||
- Activity log query performance
|
|
||||||
- Storage usage
|
|
||||||
|
|
||||||
**Business:**
|
|
||||||
- Faster response to orders
|
|
||||||
- Reduced missed notifications
|
|
||||||
- Better audit trail
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Timeline
|
|
||||||
|
|
||||||
**Week 1: Dynamic URLs + Activity Log**
|
|
||||||
- Day 1-2: Dynamic URLs implementation
|
|
||||||
- Day 3-5: Activity Log backend
|
|
||||||
- Day 6-7: Activity Log frontend
|
|
||||||
|
|
||||||
**Week 2: Rich Content**
|
|
||||||
- Day 1-3: Icons and images
|
|
||||||
- Day 4-5: Testing and polish
|
|
||||||
- Day 6-7: Documentation
|
|
||||||
|
|
||||||
**Week 3: Notification Actions**
|
|
||||||
- Day 1-3: Action handlers
|
|
||||||
- Day 4-5: Testing
|
|
||||||
- Day 6-7: Documentation and release
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Conclusion
|
|
||||||
|
|
||||||
This plan provides a comprehensive roadmap for enhancing the notification system with:
|
|
||||||
1. ✅ Customer email clarification (no changes needed)
|
|
||||||
2. ✅ Activity log system (custom build)
|
|
||||||
3. ✅ Dynamic push URLs (event-specific)
|
|
||||||
4. ✅ Rich notification content (icons, images, actions)
|
|
||||||
|
|
||||||
All enhancements are designed to improve admin experience while maintaining compatibility with WooCommerce's existing systems.
|
|
||||||
@@ -1,372 +0,0 @@
|
|||||||
# Notification System Implementation Status
|
|
||||||
|
|
||||||
**Last Updated:** November 11, 2025, 5:47 PM (GMT+7)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✅ Completed Features
|
|
||||||
|
|
||||||
### 1. UI/UX Refinements
|
|
||||||
- [x] Simplified Channels page
|
|
||||||
- [x] Removed redundant badges and toggles
|
|
||||||
- [x] Cleaned up Events page
|
|
||||||
- [x] Improved visual hierarchy
|
|
||||||
|
|
||||||
### 2. Toggle Logic Fixes
|
|
||||||
- [x] Fixed `get_json_params()` for POST data
|
|
||||||
- [x] Fixed data structure paths
|
|
||||||
- [x] Removed race conditions
|
|
||||||
- [x] All toggles working correctly
|
|
||||||
|
|
||||||
### 3. Activity Log Backend
|
|
||||||
- [x] Database table created
|
|
||||||
- [x] Logger class implemented
|
|
||||||
- [x] REST API endpoints
|
|
||||||
- [x] Query and filter system
|
|
||||||
- [x] Statistics system
|
|
||||||
- [x] Cleanup functionality
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚧 In Progress / Next Steps
|
|
||||||
|
|
||||||
### 1. Dynamic Push Notification URLs
|
|
||||||
|
|
||||||
**Status:** Planned
|
|
||||||
|
|
||||||
**Implementation:**
|
|
||||||
|
|
||||||
```php
|
|
||||||
// Add to PushNotificationHandler.php
|
|
||||||
public static function get_notification_url($event_id, $variables = []) {
|
|
||||||
$settings = get_option('woonoow_push_notification_settings', []);
|
|
||||||
|
|
||||||
// Get URL template for event
|
|
||||||
$url_templates = $settings['url_templates'] ?? [];
|
|
||||||
$template = $url_templates[$event_id] ?? $settings['default_url'] ?? '/wp-admin/admin.php?page=woonoow#/orders';
|
|
||||||
|
|
||||||
// Parse variables
|
|
||||||
foreach ($variables as $key => $value) {
|
|
||||||
$template = str_replace('{' . $key . '}', $value, $template);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $template;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Usage:**
|
|
||||||
```php
|
|
||||||
$url = PushNotificationHandler::get_notification_url('order_placed', [
|
|
||||||
'order_id' => 1234
|
|
||||||
]);
|
|
||||||
// Result: /wp-admin/admin.php?page=woonoow#/orders/1234
|
|
||||||
```
|
|
||||||
|
|
||||||
**Frontend:**
|
|
||||||
- Add URL template field to ChannelConfig.tsx
|
|
||||||
- Show available variables
|
|
||||||
- Preview parsed URL
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2. Rich Notification Content
|
|
||||||
|
|
||||||
**Status:** Planned
|
|
||||||
|
|
||||||
**Implementation:**
|
|
||||||
|
|
||||||
```php
|
|
||||||
// Add to PushNotificationHandler.php
|
|
||||||
public static function get_notification_content($event_id, $data = []) {
|
|
||||||
$settings = get_option('woonoow_push_notification_settings', []);
|
|
||||||
|
|
||||||
// Get icon
|
|
||||||
$icons = [
|
|
||||||
'order_placed' => '🛒',
|
|
||||||
'order_processing' => '⚙️',
|
|
||||||
'order_completed' => '✅',
|
|
||||||
'low_stock' => '📦',
|
|
||||||
'out_of_stock' => '🚫',
|
|
||||||
'new_customer' => '👤',
|
|
||||||
];
|
|
||||||
$icon = $icons[$event_id] ?? '🔔';
|
|
||||||
|
|
||||||
// Get image
|
|
||||||
$image = null;
|
|
||||||
if ($settings['show_product_images'] && isset($data['product_id'])) {
|
|
||||||
$product = wc_get_product($data['product_id']);
|
|
||||||
$image = $product ? wp_get_attachment_url($product->get_image_id()) : null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get badge (store logo)
|
|
||||||
$badge = $settings['show_store_logo'] ? get_site_icon_url() : null;
|
|
||||||
|
|
||||||
return [
|
|
||||||
'icon' => $icon,
|
|
||||||
'image' => $image,
|
|
||||||
'badge' => $badge,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3. Activity Log Frontend
|
|
||||||
|
|
||||||
**Status:** Planned
|
|
||||||
|
|
||||||
**Files to Create:**
|
|
||||||
|
|
||||||
1. **`admin-spa/src/routes/ActivityLog/index.tsx`**
|
|
||||||
```typescript
|
|
||||||
import React from 'react';
|
|
||||||
import { useQuery } from '@tanstack/react-query';
|
|
||||||
import { api } from '@/lib/api';
|
|
||||||
import { __ } from '@/lib/i18n';
|
|
||||||
|
|
||||||
export default function ActivityLog() {
|
|
||||||
const [page, setPage] = React.useState(1);
|
|
||||||
const [filters, setFilters] = React.useState({});
|
|
||||||
|
|
||||||
const { data, isLoading } = useQuery({
|
|
||||||
queryKey: ['activity-log', page, filters],
|
|
||||||
queryFn: () => api.get('/activity-log', { page, ...filters }),
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className="p-6">
|
|
||||||
<h1>{__('Activity Log')}</h1>
|
|
||||||
{/* Filters */}
|
|
||||||
{/* Activity list */}
|
|
||||||
{/* Pagination */}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **`admin-spa/src/routes/ActivityLog/ActivityItem.tsx`**
|
|
||||||
```typescript
|
|
||||||
export function ActivityItem({ activity }: { activity: any }) {
|
|
||||||
return (
|
|
||||||
<div className="flex items-start gap-4 p-4 border-b">
|
|
||||||
<div className="w-10 h-10 rounded-full bg-primary/10 flex items-center justify-center">
|
|
||||||
{getActionIcon(activity.action)}
|
|
||||||
</div>
|
|
||||||
<div className="flex-1">
|
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<span className="font-medium">{activity.user_name}</span>
|
|
||||||
<span className="text-sm text-muted-foreground">
|
|
||||||
{activity.action}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<p className="text-sm text-muted-foreground">
|
|
||||||
{activity.description}
|
|
||||||
</p>
|
|
||||||
<span className="text-xs text-muted-foreground">
|
|
||||||
{formatDate(activity.created_at)}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Add to navigation tree**
|
|
||||||
```typescript
|
|
||||||
// admin-spa/src/lib/nav/tree.ts
|
|
||||||
{
|
|
||||||
key: 'activity-log',
|
|
||||||
label: __('Activity Log'),
|
|
||||||
path: '/activity-log',
|
|
||||||
icon: History,
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 4. WooCommerce Hooks Integration
|
|
||||||
|
|
||||||
**Status:** Planned
|
|
||||||
|
|
||||||
**Implementation:**
|
|
||||||
|
|
||||||
```php
|
|
||||||
// Create: includes/Core/ActivityLog/WooCommerceHooks.php
|
|
||||||
namespace WooNooW\Core\ActivityLog;
|
|
||||||
|
|
||||||
class WooCommerceHooks {
|
|
||||||
public static function init() {
|
|
||||||
// Orders
|
|
||||||
add_action('woocommerce_new_order', [__CLASS__, 'log_order_created'], 10, 1);
|
|
||||||
add_action('woocommerce_update_order', [__CLASS__, 'log_order_updated'], 10, 1);
|
|
||||||
add_action('woocommerce_order_status_changed', [__CLASS__, 'log_order_status_changed'], 10, 4);
|
|
||||||
|
|
||||||
// Products
|
|
||||||
add_action('woocommerce_new_product', [__CLASS__, 'log_product_created'], 10, 1);
|
|
||||||
add_action('woocommerce_update_product', [__CLASS__, 'log_product_updated'], 10, 1);
|
|
||||||
add_action('woocommerce_product_set_stock', [__CLASS__, 'log_stock_changed'], 10, 1);
|
|
||||||
|
|
||||||
// Customers
|
|
||||||
add_action('woocommerce_created_customer', [__CLASS__, 'log_customer_created'], 10, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function log_order_created($order_id) {
|
|
||||||
$order = wc_get_order($order_id);
|
|
||||||
Logger::log(
|
|
||||||
'order.created',
|
|
||||||
'order',
|
|
||||||
$order_id,
|
|
||||||
sprintf(__('Order #%d created', 'woonoow'), $order_id),
|
|
||||||
[
|
|
||||||
'total' => $order->get_total(),
|
|
||||||
'status' => $order->get_status(),
|
|
||||||
'customer_id' => $order->get_customer_id(),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// ... more hooks
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Register in Bootstrap:**
|
|
||||||
```php
|
|
||||||
use WooNooW\Core\ActivityLog\WooCommerceHooks;
|
|
||||||
|
|
||||||
// In Bootstrap::init()
|
|
||||||
WooCommerceHooks::init();
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📋 Implementation Checklist
|
|
||||||
|
|
||||||
### Dynamic URLs
|
|
||||||
- [ ] Add URL template storage to push settings
|
|
||||||
- [ ] Implement `get_notification_url()` method
|
|
||||||
- [ ] Add template variable parsing
|
|
||||||
- [ ] Update notification sending to use dynamic URLs
|
|
||||||
- [ ] Add UI for URL template configuration
|
|
||||||
- [ ] Test with all event types
|
|
||||||
|
|
||||||
### Rich Content
|
|
||||||
- [ ] Add icon mapping for events
|
|
||||||
- [ ] Implement image fetching logic
|
|
||||||
- [ ] Add badge (store logo) support
|
|
||||||
- [ ] Update push notification payload
|
|
||||||
- [ ] Test on different browsers
|
|
||||||
- [ ] Test on mobile devices
|
|
||||||
|
|
||||||
### Activity Log Frontend
|
|
||||||
- [ ] Create ActivityLog route component
|
|
||||||
- [ ] Create ActivityItem component
|
|
||||||
- [ ] Create Filters component
|
|
||||||
- [ ] Add to navigation tree
|
|
||||||
- [ ] Implement pagination
|
|
||||||
- [ ] Implement search
|
|
||||||
- [ ] Add real-time updates (optional)
|
|
||||||
|
|
||||||
### WooCommerce Hooks
|
|
||||||
- [ ] Create WooCommerceHooks class
|
|
||||||
- [ ] Hook into order events
|
|
||||||
- [ ] Hook into product events
|
|
||||||
- [ ] Hook into customer events
|
|
||||||
- [ ] Hook into notification events
|
|
||||||
- [ ] Test all hooks
|
|
||||||
- [ ] Verify logging accuracy
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 Priority Order
|
|
||||||
|
|
||||||
1. **High Priority (This Week)**
|
|
||||||
- Dynamic push notification URLs
|
|
||||||
- WooCommerce hooks integration
|
|
||||||
- Activity log frontend (basic)
|
|
||||||
|
|
||||||
2. **Medium Priority (Next Week)**
|
|
||||||
- Rich notification content
|
|
||||||
- Activity log frontend (advanced filters)
|
|
||||||
- Real-time updates
|
|
||||||
|
|
||||||
3. **Low Priority (Future)**
|
|
||||||
- Notification actions
|
|
||||||
- Advanced analytics
|
|
||||||
- Export functionality
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📊 Success Metrics
|
|
||||||
|
|
||||||
**Technical:**
|
|
||||||
- [ ] All toggles working correctly
|
|
||||||
- [ ] Activity log queries < 100ms
|
|
||||||
- [ ] Push notifications delivered < 1s
|
|
||||||
- [ ] Zero race conditions
|
|
||||||
|
|
||||||
**User Experience:**
|
|
||||||
- [ ] Click-through rate on notifications > 50%
|
|
||||||
- [ ] Time to action after notification < 30s
|
|
||||||
- [ ] User satisfaction score > 4.5/5
|
|
||||||
|
|
||||||
**Business:**
|
|
||||||
- [ ] Faster response to orders (measure baseline)
|
|
||||||
- [ ] Reduced missed notifications (track count)
|
|
||||||
- [ ] Better audit trail (compliance ready)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚀 Quick Start for Next Session
|
|
||||||
|
|
||||||
1. **Test Activity Log Backend:**
|
|
||||||
```bash
|
|
||||||
# Create test activity
|
|
||||||
curl -X POST http://localhost/wp-json/woonoow/v1/activity-log \
|
|
||||||
-H "Content-Type: application/json" \
|
|
||||||
-d '{"action":"test.action","object_type":"test","object_id":1,"description":"Test activity"}'
|
|
||||||
|
|
||||||
# Get activities
|
|
||||||
curl http://localhost/wp-json/woonoow/v1/activity-log
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Implement Dynamic URLs:**
|
|
||||||
- Open `PushNotificationHandler.php`
|
|
||||||
- Add `get_notification_url()` method
|
|
||||||
- Update `send_notification()` to use it
|
|
||||||
|
|
||||||
3. **Create Activity Log UI:**
|
|
||||||
- Create `admin-spa/src/routes/ActivityLog/index.tsx`
|
|
||||||
- Add to navigation tree
|
|
||||||
- Test API integration
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📚 Documentation
|
|
||||||
|
|
||||||
**Created:**
|
|
||||||
- [x] NOTIFICATION_ENHANCEMENTS_PLAN.md
|
|
||||||
- [x] NOTIFICATION_IMPLEMENTATION_STATUS.md (this file)
|
|
||||||
- [x] NOTIFICATION_LOGIC.md
|
|
||||||
|
|
||||||
**To Create:**
|
|
||||||
- [ ] ACTIVITY_LOG_GUIDE.md
|
|
||||||
- [ ] PUSH_NOTIFICATION_GUIDE.md
|
|
||||||
- [ ] NOTIFICATION_HOOKS_REFERENCE.md
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✅ Summary
|
|
||||||
|
|
||||||
**Completed Today:**
|
|
||||||
1. UI/UX refinements (Channels + Events pages)
|
|
||||||
2. Toggle logic fixes (all working correctly)
|
|
||||||
3. Activity log backend (database + API)
|
|
||||||
4. Comprehensive planning documents
|
|
||||||
|
|
||||||
**Ready for Implementation:**
|
|
||||||
1. Dynamic push notification URLs
|
|
||||||
2. Rich notification content
|
|
||||||
3. Activity log frontend
|
|
||||||
4. WooCommerce hooks integration
|
|
||||||
|
|
||||||
**All systems are production-ready and well-documented!** 🎉
|
|
||||||
@@ -1,140 +0,0 @@
|
|||||||
# Notification Logic Documentation
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
The notification system has two levels of control:
|
|
||||||
1. **Global Channel Toggle** - Enable/disable entire channel (Channels page)
|
|
||||||
2. **Per-Event Channel Toggle** - Enable/disable channel for specific event (Events page)
|
|
||||||
|
|
||||||
Both must be enabled for a notification to be sent.
|
|
||||||
|
|
||||||
## Toggle Hierarchy
|
|
||||||
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────┐
|
|
||||||
│ Global Channel Toggle (Channels Page) │
|
|
||||||
│ - Affects ALL events │
|
|
||||||
│ - Stored in wp_options │
|
|
||||||
│ - woonoow_email_notifications_enabled │
|
|
||||||
│ - woonoow_push_notifications_enabled │
|
|
||||||
└─────────────────────────────────────────┘
|
|
||||||
↓
|
|
||||||
┌─────────────────────────────────────────┐
|
|
||||||
│ Per-Event Channel Toggle (Events Page) │
|
|
||||||
│ - Affects specific event only │
|
|
||||||
│ - Stored in woonoow_notification_settings│
|
|
||||||
│ - Independent per event │
|
|
||||||
└─────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
## Decision Logic
|
|
||||||
|
|
||||||
```php
|
|
||||||
// Notification will be sent if:
|
|
||||||
if (channel_globally_enabled && event_channel_enabled) {
|
|
||||||
send_notification();
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Examples
|
|
||||||
|
|
||||||
### Example 1: Email Disabled Globally
|
|
||||||
```
|
|
||||||
Global Email Toggle: OFF
|
|
||||||
Event "Order Placed" Email Toggle: ON
|
|
||||||
Result: ❌ No email sent
|
|
||||||
```
|
|
||||||
|
|
||||||
### Example 2: Email Enabled Globally, Disabled for Event
|
|
||||||
```
|
|
||||||
Global Email Toggle: ON
|
|
||||||
Event "Order Placed" Email Toggle: OFF
|
|
||||||
Result: ❌ No email sent
|
|
||||||
```
|
|
||||||
|
|
||||||
### Example 3: Both Enabled
|
|
||||||
```
|
|
||||||
Global Email Toggle: ON
|
|
||||||
Event "Order Placed" Email Toggle: ON
|
|
||||||
Result: ✅ Email sent
|
|
||||||
```
|
|
||||||
|
|
||||||
## Implementation
|
|
||||||
|
|
||||||
### NotificationManager Class
|
|
||||||
|
|
||||||
Located at: `includes/Core/Notifications/NotificationManager.php`
|
|
||||||
|
|
||||||
**Key Methods:**
|
|
||||||
|
|
||||||
1. `is_channel_enabled($channel_id)` - Check global channel state
|
|
||||||
2. `is_event_channel_enabled($event_id, $channel_id)` - Check per-event state
|
|
||||||
3. `should_send_notification($event_id, $channel_id)` - Validate both
|
|
||||||
4. `send($event_id, $channel_id, $data)` - Send notification
|
|
||||||
|
|
||||||
### Usage Example
|
|
||||||
|
|
||||||
```php
|
|
||||||
use WooNooW\Core\Notifications\NotificationManager;
|
|
||||||
|
|
||||||
// Check if notification should be sent
|
|
||||||
if (NotificationManager::should_send_notification('order_placed', 'email')) {
|
|
||||||
NotificationManager::send('order_placed', 'email', [
|
|
||||||
'order_id' => 123,
|
|
||||||
'customer_email' => 'customer@example.com',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Frontend Integration
|
|
||||||
|
|
||||||
### Channels Page (`Channels.tsx`)
|
|
||||||
|
|
||||||
- Shows global enable/disable toggle
|
|
||||||
- Affects all events
|
|
||||||
- API: `POST /notifications/channels/toggle`
|
|
||||||
- Params: `{ channelId, enabled }`
|
|
||||||
|
|
||||||
### Events Page (`Events.tsx`)
|
|
||||||
|
|
||||||
- Shows per-event channel toggles
|
|
||||||
- Independent for each event
|
|
||||||
- API: `POST /notifications/events/update`
|
|
||||||
- Params: `{ eventId, channels: { [channelId]: { enabled, recipient } } }`
|
|
||||||
|
|
||||||
## Storage
|
|
||||||
|
|
||||||
### Global Channel State
|
|
||||||
```php
|
|
||||||
// Email
|
|
||||||
get_option('woonoow_email_notifications_enabled', true);
|
|
||||||
|
|
||||||
// Push
|
|
||||||
get_option('woonoow_push_notifications_enabled', true);
|
|
||||||
```
|
|
||||||
|
|
||||||
### Per-Event Channel State
|
|
||||||
```php
|
|
||||||
$settings = get_option('woonoow_notification_settings', []);
|
|
||||||
$settings['order_placed']['channels']['email']['enabled'] = true;
|
|
||||||
$settings['order_placed']['channels']['email']['recipient'] = 'customer';
|
|
||||||
```
|
|
||||||
|
|
||||||
## Testing Checklist
|
|
||||||
|
|
||||||
- [ ] Disable email globally → No emails sent for any event
|
|
||||||
- [ ] Enable email globally, disable for specific event → Email sent for other events only
|
|
||||||
- [ ] Enable both → Email sent
|
|
||||||
- [ ] Same tests for push notifications
|
|
||||||
- [ ] Toggle persistence across page reloads
|
|
||||||
- [ ] UI reflects current state correctly
|
|
||||||
- [ ] Toast notifications on toggle
|
|
||||||
- [ ] Green icon when enabled, gray when disabled
|
|
||||||
|
|
||||||
## Future Enhancements
|
|
||||||
|
|
||||||
1. **Batch Operations** - Enable/disable multiple events at once
|
|
||||||
2. **Channel Priority** - Set fallback channels
|
|
||||||
3. **Scheduling** - Delay or schedule notifications
|
|
||||||
4. **Rate Limiting** - Prevent notification spam
|
|
||||||
5. **Analytics** - Track notification delivery rates
|
|
||||||
@@ -1,350 +0,0 @@
|
|||||||
# 🎉 Notification System Refactor - COMPLETE!
|
|
||||||
|
|
||||||
**Date:** November 11, 2025
|
|
||||||
**Time:** 6:52 PM - 8:25 PM (GMT+7)
|
|
||||||
**Duration:** ~1 hour 33 minutes
|
|
||||||
**Status:** ✅ **COMPLETE & READY FOR TESTING**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📊 Summary
|
|
||||||
|
|
||||||
Successfully refactored the notification system to support **both Staff and Customer notifications** with a unified architecture and separate UIs.
|
|
||||||
|
|
||||||
### Key Achievement
|
|
||||||
- ✅ **70-80% code reuse** between Staff and Customer
|
|
||||||
- ✅ **Clear separation** of concerns
|
|
||||||
- ✅ **Scalable architecture** for future expansion
|
|
||||||
- ✅ **Modern UI/UX** following industry best practices
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✅ What Was Implemented
|
|
||||||
|
|
||||||
### 1. Backend API (100% Complete)
|
|
||||||
|
|
||||||
**File:** `includes/Api/NotificationsController.php`
|
|
||||||
|
|
||||||
**New Endpoints:**
|
|
||||||
- `GET /woonoow/v1/notifications/staff/events` - Returns staff-only events
|
|
||||||
- `GET /woonoow/v1/notifications/customer/events` - Returns customer-only events
|
|
||||||
|
|
||||||
**Changes:**
|
|
||||||
- Added `recipient_type` field to all events (`'staff'` or `'customer'`)
|
|
||||||
- Created `get_all_events()` private helper method
|
|
||||||
- Implemented filtering logic based on `recipient_type`
|
|
||||||
- All existing endpoints remain functional
|
|
||||||
|
|
||||||
**Event Classification:**
|
|
||||||
```php
|
|
||||||
Staff Events (recipient_type: 'staff'):
|
|
||||||
- order_placed (New order notification for admin)
|
|
||||||
- order_cancelled (Order cancellation alert)
|
|
||||||
- low_stock (Low stock alert)
|
|
||||||
- out_of_stock (Out of stock alert)
|
|
||||||
|
|
||||||
Customer Events (recipient_type: 'customer'):
|
|
||||||
- order_processing (Order is being processed)
|
|
||||||
- order_completed (Order completed)
|
|
||||||
- order_refunded (Order refunded)
|
|
||||||
- new_customer (New account created)
|
|
||||||
- customer_note (Note added to order)
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2. Main Notifications Hub (100% Complete)
|
|
||||||
|
|
||||||
**File:** `admin-spa/src/routes/Settings/Notifications.tsx`
|
|
||||||
|
|
||||||
**Features:**
|
|
||||||
- Card-based layout with 3 sections
|
|
||||||
- **Staff Notifications** card → `/settings/notifications/staff`
|
|
||||||
- **Customer Notifications** card → `/settings/notifications/customer`
|
|
||||||
- **Activity Log** card (coming soon, disabled)
|
|
||||||
- Clear descriptions and icons for each section
|
|
||||||
- Modern, intuitive navigation
|
|
||||||
|
|
||||||
**UI Structure:**
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────┐
|
|
||||||
│ Settings → Notifications │
|
|
||||||
├─────────────────────────────────────┤
|
|
||||||
│ ┌──────────────┐ ┌──────────────┐ │
|
|
||||||
│ │ Staff │ │ Customer │ │
|
|
||||||
│ │ Notifications│ │ Notifications│ │
|
|
||||||
│ │ [Configure] │ │ [Configure] │ │
|
|
||||||
│ └──────────────┘ └──────────────┘ │
|
|
||||||
│ ┌──────────────┐ │
|
|
||||||
│ │ Activity Log │ │
|
|
||||||
│ │ [Coming Soon]│ │
|
|
||||||
│ └──────────────┘ │
|
|
||||||
└─────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3. Staff Notifications (100% Complete)
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- `admin-spa/src/routes/Settings/Notifications/Staff.tsx` (Main page)
|
|
||||||
- `admin-spa/src/routes/Settings/Notifications/Staff/Channels.tsx`
|
|
||||||
- `admin-spa/src/routes/Settings/Notifications/Staff/Events.tsx`
|
|
||||||
|
|
||||||
**Features:**
|
|
||||||
- **Channels Tab:**
|
|
||||||
- Email (Built-in, enabled by default)
|
|
||||||
- Push Notifications (Built-in, with subscription)
|
|
||||||
- Toggle switches for enable/disable
|
|
||||||
- Configure buttons for each channel
|
|
||||||
- "Extend with Addons" section (WhatsApp, Telegram, SMS)
|
|
||||||
|
|
||||||
- **Events Tab:**
|
|
||||||
- Uses `/notifications/staff/events` endpoint
|
|
||||||
- Categories: Orders, Products, Customers
|
|
||||||
- Per-event, per-channel toggles
|
|
||||||
- Real-time updates with React Query
|
|
||||||
- Shows recipient type
|
|
||||||
|
|
||||||
- **Templates Tab:**
|
|
||||||
- Reuses existing Templates component
|
|
||||||
- Email and Push templates
|
|
||||||
- Template editor
|
|
||||||
|
|
||||||
**Route:** `/settings/notifications/staff`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 4. Customer Notifications (100% Complete)
|
|
||||||
|
|
||||||
**Files:**
|
|
||||||
- `admin-spa/src/routes/Settings/Notifications/Customer.tsx` (Main page)
|
|
||||||
- `admin-spa/src/routes/Settings/Notifications/Customer/Channels.tsx`
|
|
||||||
- `admin-spa/src/routes/Settings/Notifications/Customer/Events.tsx`
|
|
||||||
|
|
||||||
**Features:**
|
|
||||||
- **Channels Tab:**
|
|
||||||
- Email (Built-in, always enabled)
|
|
||||||
- Push Notifications (Built-in, requires customer opt-in)
|
|
||||||
- "Extend with Addons" section (WhatsApp, Telegram, SMS)
|
|
||||||
- Customer preferences information
|
|
||||||
- Consistent UI with Staff page
|
|
||||||
|
|
||||||
- **Events Tab:**
|
|
||||||
- Uses `/notifications/customer/events` endpoint
|
|
||||||
- Categories: Orders, Customers
|
|
||||||
- Per-event, per-channel toggles
|
|
||||||
- Customer-specific events only
|
|
||||||
- Shows recipient type
|
|
||||||
|
|
||||||
- **Templates Tab:**
|
|
||||||
- Reuses existing Templates component
|
|
||||||
- Customer email templates
|
|
||||||
- Template editor
|
|
||||||
|
|
||||||
**Route:** `/settings/notifications/customer`
|
|
||||||
|
|
||||||
**Customer Preferences Info:**
|
|
||||||
- My Account → Notification Preferences
|
|
||||||
- Unsubscribe links in emails
|
|
||||||
- Browser push notification settings
|
|
||||||
- Note about transactional emails being required
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 5. Routes Registration (100% Complete)
|
|
||||||
|
|
||||||
**File:** `admin-spa/src/App.tsx`
|
|
||||||
|
|
||||||
**Added Routes:**
|
|
||||||
```typescript
|
|
||||||
import StaffNotifications from '@/routes/Settings/Notifications/Staff';
|
|
||||||
import CustomerNotifications from '@/routes/Settings/Notifications/Customer';
|
|
||||||
|
|
||||||
<Route path="/settings/notifications/staff" element={<StaffNotifications />} />
|
|
||||||
<Route path="/settings/notifications/customer" element={<CustomerNotifications />} />
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🐛 Bugs Fixed
|
|
||||||
|
|
||||||
### Issue 1: Staff Route Not Working
|
|
||||||
**Problem:** `/settings/notifications/staff` showed blank page
|
|
||||||
**Cause:** Route not registered in App.tsx
|
|
||||||
**Fix:** Added route registration and fixed import paths
|
|
||||||
|
|
||||||
### Issue 2: Customer Channels Inconsistent with Staff
|
|
||||||
**Problem:** Customer Channels page had different layout than Staff
|
|
||||||
**Cause:** Different component structure
|
|
||||||
**Fix:** Matched Customer Channels layout to Staff with addon section
|
|
||||||
|
|
||||||
### Issue 3: Customer Events Showing "No Events"
|
|
||||||
**Problem:** Customer Events tab showed "No Events" message
|
|
||||||
**Cause:** Backend filtering logic using `reset()` on channels array
|
|
||||||
**Fix:** Changed to use `recipient_type` field for filtering
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📁 Files Created/Modified
|
|
||||||
|
|
||||||
### Created (7 files):
|
|
||||||
1. `admin-spa/src/routes/Settings/Notifications/Staff.tsx`
|
|
||||||
2. `admin-spa/src/routes/Settings/Notifications/Staff/Channels.tsx`
|
|
||||||
3. `admin-spa/src/routes/Settings/Notifications/Staff/Events.tsx`
|
|
||||||
4. `admin-spa/src/routes/Settings/Notifications/Customer.tsx`
|
|
||||||
5. `admin-spa/src/routes/Settings/Notifications/Customer/Channels.tsx`
|
|
||||||
6. `admin-spa/src/routes/Settings/Notifications/Customer/Events.tsx`
|
|
||||||
7. `NOTIFICATION_REFACTOR_STATUS.md` (documentation)
|
|
||||||
|
|
||||||
### Modified (3 files):
|
|
||||||
1. `includes/Api/NotificationsController.php` (Backend API)
|
|
||||||
2. `admin-spa/src/routes/Settings/Notifications.tsx` (Main hub)
|
|
||||||
3. `admin-spa/src/App.tsx` (Route registration)
|
|
||||||
|
|
||||||
**Total Lines of Code:** ~1,800+
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 Architecture
|
|
||||||
|
|
||||||
```
|
|
||||||
Settings → Notifications (Main Hub)
|
|
||||||
├── Staff Notifications (/settings/notifications/staff)
|
|
||||||
│ ├── Channels Tab
|
|
||||||
│ │ ├── Email (Built-in, toggleable)
|
|
||||||
│ │ ├── Push Notifications (Built-in, toggleable)
|
|
||||||
│ │ └── Extend with Addons (WhatsApp, Telegram, SMS)
|
|
||||||
│ ├── Events Tab
|
|
||||||
│ │ ├── Orders (order_placed, order_cancelled)
|
|
||||||
│ │ ├── Products (low_stock, out_of_stock)
|
|
||||||
│ │ └── Customers (staff view)
|
|
||||||
│ └── Templates Tab
|
|
||||||
│ └── Staff email/push templates
|
|
||||||
│
|
|
||||||
└── Customer Notifications (/settings/notifications/customer)
|
|
||||||
├── Channels Tab
|
|
||||||
│ ├── Email (Built-in, always enabled)
|
|
||||||
│ ├── Push Notifications (Requires opt-in)
|
|
||||||
│ └── Extend with Addons (WhatsApp, Telegram, SMS)
|
|
||||||
├── Events Tab
|
|
||||||
│ ├── Orders (order_processing, order_completed, order_refunded)
|
|
||||||
│ └── Customers (new_customer, customer_note)
|
|
||||||
└── Templates Tab
|
|
||||||
└── Customer email/push templates
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✅ Testing Checklist
|
|
||||||
|
|
||||||
### Navigation
|
|
||||||
- [x] Main hub shows 3 cards (Staff, Customer, Activity Log)
|
|
||||||
- [ ] Click "Configure" on Staff card → Goes to `/settings/notifications/staff`
|
|
||||||
- [ ] Click "Configure" on Customer card → Goes to `/settings/notifications/customer`
|
|
||||||
- [ ] Click "Back to Notifications" → Returns to main hub
|
|
||||||
- [ ] All tabs work (Channels, Events, Templates)
|
|
||||||
|
|
||||||
### Staff Section
|
|
||||||
- [ ] Channels tab shows Email and Push with toggles
|
|
||||||
- [ ] Events tab shows staff events (order_placed, low_stock, etc.)
|
|
||||||
- [ ] Toggle switches work and persist
|
|
||||||
- [ ] Templates tab loads correctly
|
|
||||||
- [ ] Addon section shows WhatsApp, Telegram, SMS cards
|
|
||||||
|
|
||||||
### Customer Section
|
|
||||||
- [ ] Channels tab shows Email and Push (no toggles)
|
|
||||||
- [ ] Events tab shows customer events (order_processing, order_completed, etc.)
|
|
||||||
- [ ] Toggle switches work and persist
|
|
||||||
- [ ] Templates tab loads correctly
|
|
||||||
- [ ] Addon section shows WhatsApp, Telegram, SMS cards
|
|
||||||
- [ ] Customer preferences info displayed
|
|
||||||
|
|
||||||
### Data Persistence
|
|
||||||
- [ ] Toggle staff event → Refresh → Stays toggled
|
|
||||||
- [ ] Toggle customer event → Refresh → Stays toggled
|
|
||||||
- [ ] Settings saved to database correctly
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚀 What's Next (Optional Enhancements)
|
|
||||||
|
|
||||||
### Phase 4: Templates with Recipient Filter (Optional)
|
|
||||||
- Add `recipientType` prop to Templates component
|
|
||||||
- Filter templates by staff/customer
|
|
||||||
- Show only relevant templates per section
|
|
||||||
|
|
||||||
### Phase 5: Activity Log UI (Future)
|
|
||||||
- Build frontend UI for activity log
|
|
||||||
- Show notification history
|
|
||||||
- Filter by recipient, channel, event
|
|
||||||
- Export logs
|
|
||||||
|
|
||||||
### Phase 6: Customer Preferences Page (Future)
|
|
||||||
- Build customer-facing preferences UI in customer-spa
|
|
||||||
- Allow customers to manage their notifications
|
|
||||||
- Per-event opt-in/opt-out
|
|
||||||
- Unsubscribe management
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📈 Impact
|
|
||||||
|
|
||||||
### Before
|
|
||||||
- ❌ Admin-only notifications (1-5 users)
|
|
||||||
- ❌ 10-50 notifications/day
|
|
||||||
- ❌ Incomplete feature
|
|
||||||
- ❌ Missed opportunity
|
|
||||||
|
|
||||||
### After
|
|
||||||
- ✅ Staff + Customer notifications (100-10,000+ users)
|
|
||||||
- ✅ 100-1,000+ notifications/day
|
|
||||||
- ✅ Complete, scalable feature
|
|
||||||
- ✅ 10-100x higher business impact
|
|
||||||
- ✅ Better customer experience
|
|
||||||
- ✅ Competitive advantage
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎉 Success Metrics
|
|
||||||
|
|
||||||
1. **Code Reusability:** 70-80% ✅
|
|
||||||
2. **Clear Separation:** Staff vs Customer ✅
|
|
||||||
3. **Scalability:** Easy to add new events/channels ✅
|
|
||||||
4. **User Experience:** Intuitive navigation ✅
|
|
||||||
5. **Industry Standards:** Follows Shopify/BigCommerce patterns ✅
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📝 Commits
|
|
||||||
|
|
||||||
1. `feat: Restructure notifications - Staff and Customer separation (WIP)`
|
|
||||||
2. `docs: Add notification refactor status document`
|
|
||||||
3. `fix: Register staff notifications route and fix import paths`
|
|
||||||
4. `feat: Complete Customer Notifications section`
|
|
||||||
5. `fix: Match Customer Channels to Staff layout and fix event filtering`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🙏 Acknowledgments
|
|
||||||
|
|
||||||
**User Concern Addressed:**
|
|
||||||
> "I think, yes this is absolutely good, but we did so much effort if only for admin. Or even better this feature can be reuse there in customer-spa (?)"
|
|
||||||
|
|
||||||
**Result:** Feature now supports both Staff and Customer with 70-80% code reuse! 🎉
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📞 Support
|
|
||||||
|
|
||||||
If you encounter any issues:
|
|
||||||
1. Check browser console for errors
|
|
||||||
2. Check WordPress debug log
|
|
||||||
3. Verify API endpoints return data: `/wp-json/woonoow/v1/notifications/staff/events`
|
|
||||||
4. Clear browser cache and refresh
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Status:** ✅ **READY FOR PRODUCTION**
|
|
||||||
**Confidence:** 95% (pending final user testing)
|
|
||||||
**Recommendation:** Test thoroughly, then deploy! 🚀
|
|
||||||
@@ -1,409 +0,0 @@
|
|||||||
# Notification System Refactor - Implementation Status
|
|
||||||
|
|
||||||
**Started:** November 11, 2025, 6:52 PM (GMT+7)
|
|
||||||
**Completed:** November 11, 2025, 8:02 PM (GMT+7)
|
|
||||||
**Status:** ✅ 90% Complete (Testing Pending)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✅ Phase 1 Complete: Backend + Staff Frontend
|
|
||||||
|
|
||||||
### Backend (100% Complete)
|
|
||||||
|
|
||||||
**File:** `includes/Api/NotificationsController.php`
|
|
||||||
|
|
||||||
**Changes:**
|
|
||||||
1. ✅ Added `GET /notifications/staff/events` endpoint
|
|
||||||
2. ✅ Added `GET /notifications/customer/events` endpoint
|
|
||||||
3. ✅ Created `get_all_events()` private helper method
|
|
||||||
4. ✅ Added `recipient_type` field to all events
|
|
||||||
5. ✅ Filtering logic for staff vs customer events
|
|
||||||
|
|
||||||
**Event Classification:**
|
|
||||||
- **Staff Events:** order_placed, order_cancelled, low_stock, out_of_stock
|
|
||||||
- **Customer Events:** order_processing, order_completed, order_refunded, new_customer, customer_note
|
|
||||||
|
|
||||||
### Frontend - Main Page (100% Complete)
|
|
||||||
|
|
||||||
**File:** `admin-spa/src/routes/Settings/Notifications.tsx`
|
|
||||||
|
|
||||||
**Changes:**
|
|
||||||
1. ✅ Removed tabs (Events, Channels, Templates)
|
|
||||||
2. ✅ Added card-based layout
|
|
||||||
3. ✅ Three cards: Staff Notifications, Customer Notifications, Activity Log
|
|
||||||
4. ✅ Links to `/settings/notifications/staff` and `/settings/notifications/customer`
|
|
||||||
5. ✅ Modern UI with icons and descriptions
|
|
||||||
|
|
||||||
### Frontend - Staff Section (100% Complete)
|
|
||||||
|
|
||||||
**File:** `admin-spa/src/routes/Settings/Notifications/Staff.tsx`
|
|
||||||
|
|
||||||
**Changes:**
|
|
||||||
1. ✅ Created Staff Notifications page with tabs
|
|
||||||
2. ✅ Tabs: Channels, Events, Templates
|
|
||||||
3. ✅ Back button to main Notifications page
|
|
||||||
4. ✅ Reuses existing components
|
|
||||||
|
|
||||||
**File:** `admin-spa/src/routes/Settings/Notifications/Staff/Channels.tsx`
|
|
||||||
- ✅ Copied from `Notifications/Channels.tsx`
|
|
||||||
- ✅ No changes needed (already works for staff)
|
|
||||||
|
|
||||||
**File:** `admin-spa/src/routes/Settings/Notifications/Staff/Events.tsx`
|
|
||||||
- ✅ Copied from `Notifications/Events.tsx`
|
|
||||||
- ✅ Updated to use `/notifications/staff/events` endpoint
|
|
||||||
- ✅ Updated query key to `notification-staff-events`
|
|
||||||
- ✅ Fixed import paths
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✅ Phase 2 Complete: Customer Frontend
|
|
||||||
|
|
||||||
### Customer Notifications Page
|
|
||||||
|
|
||||||
**File to Create:** `admin-spa/src/routes/Settings/Notifications/Customer.tsx`
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
import React, { useState } from 'react';
|
|
||||||
import { Link } from 'react-router-dom';
|
|
||||||
import { SettingsLayout } from '../components/SettingsLayout';
|
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
|
|
||||||
import { Button } from '@/components/ui/button';
|
|
||||||
import { __ } from '@/lib/i18n';
|
|
||||||
import { ChevronLeft } from 'lucide-react';
|
|
||||||
import CustomerChannels from './Customer/Channels';
|
|
||||||
import CustomerEvents from './Customer/Events';
|
|
||||||
import NotificationTemplates from './Templates';
|
|
||||||
|
|
||||||
export default function CustomerNotifications() {
|
|
||||||
const [activeTab, setActiveTab] = useState('channels');
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SettingsLayout
|
|
||||||
title={__('Customer Notifications')}
|
|
||||||
description={__('Configure notifications sent to customers')}
|
|
||||||
action={
|
|
||||||
<Link to="/settings/notifications">
|
|
||||||
<Button variant="ghost" size="sm">
|
|
||||||
<ChevronLeft className="mr-2 h-4 w-4" />
|
|
||||||
{__('Back to Notifications')}
|
|
||||||
</Button>
|
|
||||||
</Link>
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Tabs value={activeTab} onValueChange={setActiveTab} className="space-y-6">
|
|
||||||
<TabsList className="grid w-full grid-cols-3">
|
|
||||||
<TabsTrigger value="channels">{__('Channels')}</TabsTrigger>
|
|
||||||
<TabsTrigger value="events">{__('Events')}</TabsTrigger>
|
|
||||||
<TabsTrigger value="templates">{__('Templates')}</TabsTrigger>
|
|
||||||
</TabsList>
|
|
||||||
|
|
||||||
<TabsContent value="channels" className="space-y-4">
|
|
||||||
<CustomerChannels />
|
|
||||||
</TabsContent>
|
|
||||||
|
|
||||||
<TabsContent value="events" className="space-y-4">
|
|
||||||
<CustomerEvents />
|
|
||||||
</TabsContent>
|
|
||||||
|
|
||||||
<TabsContent value="templates" className="space-y-4">
|
|
||||||
<NotificationTemplates recipientType="customer" />
|
|
||||||
</TabsContent>
|
|
||||||
</Tabs>
|
|
||||||
</SettingsLayout>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Customer Channels Component
|
|
||||||
|
|
||||||
**File to Create:** `admin-spa/src/routes/Settings/Notifications/Customer/Channels.tsx`
|
|
||||||
|
|
||||||
**Features:**
|
|
||||||
- Email channel (always available)
|
|
||||||
- Push notifications (requires customer opt-in)
|
|
||||||
- SMS channel (addon, coming soon)
|
|
||||||
- Different messaging for customer context
|
|
||||||
|
|
||||||
### Customer Events Component
|
|
||||||
|
|
||||||
**File to Create:** `admin-spa/src/routes/Settings/Notifications/Customer/Events.tsx`
|
|
||||||
|
|
||||||
**Features:**
|
|
||||||
- Use `/notifications/customer/events` endpoint
|
|
||||||
- Query key: `notification-customer-events`
|
|
||||||
- Categories:
|
|
||||||
- **Orders:** Processing, Completed, Refunded
|
|
||||||
- **Account:** New Customer, Customer Note
|
|
||||||
- **Shipping:** (future) Shipped, Delivered, Tracking Updates
|
|
||||||
- **Marketing:** (future) Abandoned Cart, Promotions
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✅ Phase 3 Complete: Routes Registration
|
|
||||||
|
|
||||||
### Update App Routes
|
|
||||||
|
|
||||||
**File to Update:** `admin-spa/src/App.tsx`
|
|
||||||
|
|
||||||
**Add Routes:**
|
|
||||||
```typescript
|
|
||||||
<Route path="/settings/notifications/staff" element={<StaffNotifications />} />
|
|
||||||
<Route path="/settings/notifications/customer" element={<CustomerNotifications />} />
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚧 Phase 4: Templates Update (To Do)
|
|
||||||
|
|
||||||
### Update Templates Component
|
|
||||||
|
|
||||||
**File to Update:** `admin-spa/src/routes/Settings/Notifications/Templates.tsx`
|
|
||||||
|
|
||||||
**Changes:**
|
|
||||||
- Accept `recipientType` prop (`'staff' | 'customer'`)
|
|
||||||
- Filter templates by recipient type
|
|
||||||
- Show different template categories based on recipient
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📋 Implementation Checklist
|
|
||||||
|
|
||||||
### Phase 1: Backend + Staff (Complete ✅)
|
|
||||||
- [x] Backend: Add staff/customer endpoints
|
|
||||||
- [x] Backend: Add recipient_type to events
|
|
||||||
- [x] Backend: Filter events by recipient
|
|
||||||
- [x] Frontend: Restructure main Notifications page
|
|
||||||
- [x] Frontend: Create Staff Notifications page
|
|
||||||
- [x] Frontend: Move Channels to Staff/Channels
|
|
||||||
- [x] Frontend: Move Events to Staff/Events
|
|
||||||
- [x] Frontend: Update Staff/Events endpoint
|
|
||||||
|
|
||||||
### Phase 2: Customer Frontend (Complete ✅)
|
|
||||||
- [x] Create Customer Notifications page
|
|
||||||
- [x] Create Customer/Channels component
|
|
||||||
- [x] Create Customer/Events component
|
|
||||||
- [x] Update Customer/Events to use customer endpoint
|
|
||||||
- [x] Add customer-specific messaging
|
|
||||||
|
|
||||||
### Phase 3: Routes (Complete ✅)
|
|
||||||
- [x] Register /settings/notifications/staff route
|
|
||||||
- [x] Register /settings/notifications/customer route
|
|
||||||
- [x] Test navigation between pages
|
|
||||||
|
|
||||||
### Phase 4: Templates (Pending 📋)
|
|
||||||
- [ ] Add recipientType prop to Templates
|
|
||||||
- [ ] Filter templates by recipient
|
|
||||||
- [ ] Test template editing for both types
|
|
||||||
|
|
||||||
### Phase 5: Testing (Pending 📋)
|
|
||||||
- [ ] Test staff notifications flow
|
|
||||||
- [ ] Test customer notifications flow
|
|
||||||
- [ ] Test navigation
|
|
||||||
- [ ] Test data persistence
|
|
||||||
- [ ] Test with different events
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 Next Steps
|
|
||||||
|
|
||||||
1. **Create Customer Notifications Page**
|
|
||||||
- Copy structure from Staff.tsx
|
|
||||||
- Update titles and descriptions
|
|
||||||
- Link to Customer components
|
|
||||||
|
|
||||||
2. **Create Customer/Channels Component**
|
|
||||||
- Similar to Staff/Channels
|
|
||||||
- Add SMS channel (disabled, coming soon)
|
|
||||||
- Customer-specific messaging
|
|
||||||
|
|
||||||
3. **Create Customer/Events Component**
|
|
||||||
- Use `/notifications/customer/events`
|
|
||||||
- Query key: `notification-customer-events`
|
|
||||||
- Customer event categories
|
|
||||||
|
|
||||||
4. **Register Routes**
|
|
||||||
- Add to App.tsx
|
|
||||||
- Test navigation
|
|
||||||
|
|
||||||
5. **Update Templates**
|
|
||||||
- Add recipientType prop
|
|
||||||
- Filter by recipient
|
|
||||||
|
|
||||||
6. **Test Everything**
|
|
||||||
- End-to-end testing
|
|
||||||
- Fix any issues
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📊 Progress
|
|
||||||
|
|
||||||
**Overall:** 90% Complete
|
|
||||||
|
|
||||||
- Backend: 100% ✅
|
|
||||||
- Main Page: 100% ✅
|
|
||||||
- Staff Section: 100% ✅
|
|
||||||
- Customer Section: 100% ✅
|
|
||||||
- Routes: 100% ✅
|
|
||||||
- Templates: 0% 📋 (Optional)
|
|
||||||
- Testing: 50% 🚧 (Manual testing needed)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚀 Quick Start for Next Session
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Continue from where we left off
|
|
||||||
|
|
||||||
# 1. Create Customer Notifications page
|
|
||||||
# File: admin-spa/src/routes/Settings/Notifications/Customer.tsx
|
|
||||||
|
|
||||||
# 2. Create Customer/Channels component
|
|
||||||
# File: admin-spa/src/routes/Settings/Notifications/Customer/Channels.tsx
|
|
||||||
|
|
||||||
# 3. Create Customer/Events component
|
|
||||||
# File: admin-spa/src/routes/Settings/Notifications/Customer/Events.tsx
|
|
||||||
|
|
||||||
# 4. Register routes in App.tsx
|
|
||||||
|
|
||||||
# 5. Test the flow
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📚 Architecture
|
|
||||||
|
|
||||||
```
|
|
||||||
Settings → Notifications (Main Hub)
|
|
||||||
├── Staff Notifications (/settings/notifications/staff)
|
|
||||||
│ ├── Channels Tab
|
|
||||||
│ │ ├── Email (Built-in)
|
|
||||||
│ │ └── Push Notifications (Built-in)
|
|
||||||
│ ├── Events Tab
|
|
||||||
│ │ ├── Orders (order_placed, order_cancelled)
|
|
||||||
│ │ ├── Products (low_stock, out_of_stock)
|
|
||||||
│ │ └── Customers (admin view)
|
|
||||||
│ └── Templates Tab
|
|
||||||
│ └── Staff email/push templates
|
|
||||||
│
|
|
||||||
└── Customer Notifications (/settings/notifications/customer)
|
|
||||||
├── Channels Tab
|
|
||||||
│ ├── Email (Built-in)
|
|
||||||
│ ├── Push Notifications (Requires opt-in)
|
|
||||||
│ └── SMS (Addon, coming soon)
|
|
||||||
├── Events Tab
|
|
||||||
│ ├── Orders (order_processing, order_completed, order_refunded)
|
|
||||||
│ ├── Account (new_customer, customer_note)
|
|
||||||
│ └── Shipping (future: shipped, delivered)
|
|
||||||
└── Templates Tab
|
|
||||||
└── Customer email/push templates
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✅ Success Criteria
|
|
||||||
|
|
||||||
1. **Clear Separation**
|
|
||||||
- Staff and Customer sections are visually distinct
|
|
||||||
- Easy to navigate between sections
|
|
||||||
- No confusion about which notifications are for whom
|
|
||||||
|
|
||||||
2. **Code Reusability**
|
|
||||||
- 70-80% code reuse between Staff and Customer
|
|
||||||
- Shared components where possible
|
|
||||||
- DRY principles followed
|
|
||||||
|
|
||||||
3. **Scalability**
|
|
||||||
- Easy to add new event types
|
|
||||||
- Easy to add new channels
|
|
||||||
- Easy to add new recipient types (future: vendors, partners)
|
|
||||||
|
|
||||||
4. **User Experience**
|
|
||||||
- Intuitive navigation
|
|
||||||
- Clear labeling
|
|
||||||
- Helpful descriptions
|
|
||||||
- Responsive design
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Status:** Phases 1-3 complete! Ready for testing! 🚀
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎉 Implementation Complete!
|
|
||||||
|
|
||||||
### What's Working
|
|
||||||
|
|
||||||
1. **Backend API** ✅
|
|
||||||
- `/notifications/staff/events` - Returns staff-only events
|
|
||||||
- `/notifications/customer/events` - Returns customer-only events
|
|
||||||
- Event filtering by recipient type
|
|
||||||
- All existing endpoints still work
|
|
||||||
|
|
||||||
2. **Main Notifications Hub** ✅
|
|
||||||
- Card-based layout
|
|
||||||
- Staff Notifications card → `/settings/notifications/staff`
|
|
||||||
- Customer Notifications card → `/settings/notifications/customer`
|
|
||||||
- Activity Log card (coming soon)
|
|
||||||
|
|
||||||
3. **Staff Notifications** ✅
|
|
||||||
- Channels tab (Email, Push)
|
|
||||||
- Events tab (Orders, Products, Customers)
|
|
||||||
- Templates tab
|
|
||||||
- All functionality working
|
|
||||||
|
|
||||||
4. **Customer Notifications** ✅
|
|
||||||
- Channels tab (Email, Push, SMS info)
|
|
||||||
- Events tab (Orders, Account)
|
|
||||||
- Templates tab
|
|
||||||
- Customer-specific messaging
|
|
||||||
- Opt-in information
|
|
||||||
|
|
||||||
### What to Test
|
|
||||||
|
|
||||||
1. **Navigation**
|
|
||||||
- [ ] Click "Configure" on Staff card → Should go to Staff page
|
|
||||||
- [ ] Click "Configure" on Customer card → Should go to Customer page
|
|
||||||
- [ ] Click "Back to Notifications" → Should return to main hub
|
|
||||||
|
|
||||||
2. **Staff Section**
|
|
||||||
- [ ] Channels tab shows Email and Push
|
|
||||||
- [ ] Events tab shows staff events (order_placed, low_stock, etc.)
|
|
||||||
- [ ] Toggle switches work
|
|
||||||
- [ ] Templates tab loads
|
|
||||||
|
|
||||||
3. **Customer Section**
|
|
||||||
- [ ] Channels tab shows Email, Push, SMS info
|
|
||||||
- [ ] Events tab shows customer events (order_processing, order_completed, etc.)
|
|
||||||
- [ ] Toggle switches work
|
|
||||||
- [ ] Templates tab loads
|
|
||||||
|
|
||||||
4. **Data Persistence**
|
|
||||||
- [ ] Toggle a staff event → Refresh → Should stay toggled
|
|
||||||
- [ ] Toggle a customer event → Refresh → Should stay toggled
|
|
||||||
|
|
||||||
### Known Issues
|
|
||||||
|
|
||||||
- None! Everything should work. 🎉
|
|
||||||
|
|
||||||
### Optional Enhancements (Future)
|
|
||||||
|
|
||||||
1. **Templates with Recipient Filter**
|
|
||||||
- Add `recipientType` prop to Templates component
|
|
||||||
- Filter templates by staff/customer
|
|
||||||
|
|
||||||
2. **Activity Log**
|
|
||||||
- Build frontend UI for activity log
|
|
||||||
- Show notification history
|
|
||||||
|
|
||||||
3. **Customer Preferences Page**
|
|
||||||
- Build customer-facing preferences UI
|
|
||||||
- Allow customers to manage their notifications
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Total Time:** ~1 hour 10 minutes
|
|
||||||
**Files Created:** 7
|
|
||||||
**Files Modified:** 3
|
|
||||||
**Lines of Code:** ~1,500+
|
|
||||||
|
|
||||||
**Result:** Complete notification system with Staff and Customer separation! 🎉
|
|
||||||
@@ -1,294 +0,0 @@
|
|||||||
# WooNooW Notification Strategy
|
|
||||||
|
|
||||||
## Philosophy
|
|
||||||
|
|
||||||
**Core Principle:** WooNooW provides the notification framework and email as the default channel. Additional channels (WhatsApp, Telegram, SMS, etc.) are provided by addons.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Architecture
|
|
||||||
|
|
||||||
### Core (WooNooW Plugin)
|
|
||||||
|
|
||||||
**Provides:**
|
|
||||||
1. **Notification Events System**
|
|
||||||
- Order placed
|
|
||||||
- Order status changed
|
|
||||||
- Low stock alert
|
|
||||||
- New customer registered
|
|
||||||
- etc.
|
|
||||||
|
|
||||||
2. **Email Channel (Built-in)**
|
|
||||||
- Default notification channel
|
|
||||||
- Always available
|
|
||||||
- Template system
|
|
||||||
- Queue system for bulk sending
|
|
||||||
|
|
||||||
3. **Notification Settings UI**
|
|
||||||
- Enable/disable notifications per event
|
|
||||||
- Configure which channels to use per event
|
|
||||||
- Template editor (for email)
|
|
||||||
- Channel-specific settings (provided by addons)
|
|
||||||
|
|
||||||
4. **Addon Integration Points**
|
|
||||||
- `woonoow_notification_channels` filter - Register new channels
|
|
||||||
- `woonoow_notification_send_{channel}` action - Send via channel
|
|
||||||
- `woonoow_notification_settings_{channel}` filter - Channel settings UI
|
|
||||||
- `woonoow_notification_template_{channel}` filter - Channel templates
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Settings Page Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
Notifications
|
|
||||||
├── Events (What to notify)
|
|
||||||
│ ├── Orders
|
|
||||||
│ │ ├── Order Placed
|
|
||||||
│ │ │ ├── ✓ Email (to admin)
|
|
||||||
│ │ │ ├── ✓ WhatsApp (to customer) [if addon active]
|
|
||||||
│ │ │ └── ✗ Telegram
|
|
||||||
│ │ ├── Order Completed
|
|
||||||
│ │ ├── Order Cancelled
|
|
||||||
│ │ └── Order Refunded
|
|
||||||
│ ├── Products
|
|
||||||
│ │ ├── Low Stock Alert
|
|
||||||
│ │ └── Out of Stock Alert
|
|
||||||
│ └── Customers
|
|
||||||
│ ├── New Customer
|
|
||||||
│ └── Customer Note Added
|
|
||||||
│
|
|
||||||
├── Channels (How to notify)
|
|
||||||
│ ├── Email (Built-in) ✓
|
|
||||||
│ │ ├── From Name
|
|
||||||
│ │ ├── From Email
|
|
||||||
│ │ ├── SMTP Settings (optional)
|
|
||||||
│ │ └── Templates
|
|
||||||
│ ├── WhatsApp [Addon]
|
|
||||||
│ │ ├── API Key
|
|
||||||
│ │ ├── Phone Number
|
|
||||||
│ │ └── Message Templates
|
|
||||||
│ ├── Telegram [Addon]
|
|
||||||
│ │ ├── Bot Token
|
|
||||||
│ │ ├── Chat ID
|
|
||||||
│ │ └── Message Format
|
|
||||||
│ └── SMS [Addon]
|
|
||||||
│ ├── Provider (Twilio, etc.)
|
|
||||||
│ ├── API Credentials
|
|
||||||
│ └── Message Templates
|
|
||||||
│
|
|
||||||
└── Templates
|
|
||||||
├── Email Templates
|
|
||||||
├── WhatsApp Templates [if addon active]
|
|
||||||
└── Telegram Templates [if addon active]
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Implementation
|
|
||||||
|
|
||||||
### 1. Core Notification System
|
|
||||||
|
|
||||||
```php
|
|
||||||
// includes/Core/Notifications/NotificationManager.php
|
|
||||||
class NotificationManager {
|
|
||||||
private $channels = [];
|
|
||||||
|
|
||||||
public function register_channel($id, $label, $callback) {
|
|
||||||
$this->channels[$id] = [
|
|
||||||
'label' => $label,
|
|
||||||
'callback' => $callback,
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public function send($event, $data, $channels = ['email']) {
|
|
||||||
foreach ($channels as $channel) {
|
|
||||||
if (isset($this->channels[$channel])) {
|
|
||||||
call_user_func($this->channels[$channel]['callback'], $event, $data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. Email Channel (Built-in)
|
|
||||||
|
|
||||||
```php
|
|
||||||
// includes/Core/Notifications/Channels/EmailChannel.php
|
|
||||||
class EmailChannel {
|
|
||||||
public static function init() {
|
|
||||||
add_filter('woonoow_notification_channels', [__CLASS__, 'register']);
|
|
||||||
add_action('woonoow_notification_send_email', [__CLASS__, 'send'], 10, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function register($channels) {
|
|
||||||
$channels['email'] = [
|
|
||||||
'id' => 'email',
|
|
||||||
'label' => 'Email',
|
|
||||||
'icon' => 'mail',
|
|
||||||
'builtin' => true,
|
|
||||||
];
|
|
||||||
return $channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function send($event, $data) {
|
|
||||||
// Send email using WooNooW mail queue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. Addon Example: WhatsApp Channel
|
|
||||||
|
|
||||||
```php
|
|
||||||
// woonoow-whatsapp/includes/WhatsAppChannel.php
|
|
||||||
class WhatsAppChannel {
|
|
||||||
public static function init() {
|
|
||||||
add_filter('woonoow_notification_channels', [__CLASS__, 'register']);
|
|
||||||
add_action('woonoow_notification_send_whatsapp', [__CLASS__, 'send'], 10, 2);
|
|
||||||
add_filter('woonoow_notification_settings_whatsapp', [__CLASS__, 'settings']);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function register($channels) {
|
|
||||||
$channels['whatsapp'] = [
|
|
||||||
'id' => 'whatsapp',
|
|
||||||
'label' => 'WhatsApp',
|
|
||||||
'icon' => 'message-circle',
|
|
||||||
'addon' => 'woonoow-whatsapp',
|
|
||||||
];
|
|
||||||
return $channels;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function send($event, $data) {
|
|
||||||
// Send WhatsApp message via API
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function settings() {
|
|
||||||
return [
|
|
||||||
'api_key' => get_option('woonoow_whatsapp_api_key'),
|
|
||||||
'phone_number' => get_option('woonoow_whatsapp_phone'),
|
|
||||||
];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Frontend (React SPA)
|
|
||||||
|
|
||||||
### Notifications Settings Page
|
|
||||||
|
|
||||||
```tsx
|
|
||||||
// admin-spa/src/routes/Settings/Notifications.tsx
|
|
||||||
|
|
||||||
interface NotificationChannel {
|
|
||||||
id: string;
|
|
||||||
label: string;
|
|
||||||
icon: string;
|
|
||||||
builtin?: boolean;
|
|
||||||
addon?: string;
|
|
||||||
enabled: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface NotificationEvent {
|
|
||||||
id: string;
|
|
||||||
label: string;
|
|
||||||
description: string;
|
|
||||||
category: 'orders' | 'products' | 'customers';
|
|
||||||
channels: {
|
|
||||||
[channelId: string]: {
|
|
||||||
enabled: boolean;
|
|
||||||
recipient: 'admin' | 'customer' | 'both';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function NotificationsPage() {
|
|
||||||
// Fetch available channels (core + addons)
|
|
||||||
const { data: channels } = useQuery({
|
|
||||||
queryKey: ['notification-channels'],
|
|
||||||
queryFn: () => api.get('/notifications/channels'),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Fetch notification events configuration
|
|
||||||
const { data: events } = useQuery({
|
|
||||||
queryKey: ['notification-events'],
|
|
||||||
queryFn: () => api.get('/notifications/events'),
|
|
||||||
});
|
|
||||||
|
|
||||||
return (
|
|
||||||
<SettingsLayout title="Notifications">
|
|
||||||
{/* Available Channels */}
|
|
||||||
<SettingsCard title="Notification Channels">
|
|
||||||
{channels?.map(channel => (
|
|
||||||
<ChannelCard key={channel.id} channel={channel} />
|
|
||||||
))}
|
|
||||||
</SettingsCard>
|
|
||||||
|
|
||||||
{/* Events Configuration */}
|
|
||||||
<SettingsCard title="Order Notifications">
|
|
||||||
{events?.filter(e => e.category === 'orders').map(event => (
|
|
||||||
<EventCard
|
|
||||||
key={event.id}
|
|
||||||
event={event}
|
|
||||||
channels={channels}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</SettingsCard>
|
|
||||||
|
|
||||||
{/* More categories... */}
|
|
||||||
</SettingsLayout>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Benefits
|
|
||||||
|
|
||||||
1. **Extensible:** Addons can add any notification channel
|
|
||||||
2. **Flexible:** Each event can use multiple channels
|
|
||||||
3. **User-Friendly:** Clear UI showing what's available
|
|
||||||
4. **No Bloat:** Core only includes email
|
|
||||||
5. **Addon Revenue:** Premium channels (WhatsApp, SMS) can be paid addons
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Example Addons
|
|
||||||
|
|
||||||
### Free Addons
|
|
||||||
- **WooNooW Telegram** - Send notifications via Telegram bot
|
|
||||||
- **WooNooW Discord** - Send notifications to Discord channel
|
|
||||||
|
|
||||||
### Premium Addons
|
|
||||||
- **WooNooW WhatsApp Pro** - WhatsApp Business API integration
|
|
||||||
- **WooNooW SMS** - SMS notifications via Twilio/Nexmo
|
|
||||||
- **WooNooW Push** - Browser push notifications
|
|
||||||
- **WooNooW Slack** - Team notifications via Slack
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Migration Path
|
|
||||||
|
|
||||||
**Phase 1 (Current):**
|
|
||||||
- Build notification framework
|
|
||||||
- Implement email channel
|
|
||||||
- Create settings UI with addon slots
|
|
||||||
|
|
||||||
**Phase 2:**
|
|
||||||
- Build first addon (Telegram) as proof of concept
|
|
||||||
- Document addon API
|
|
||||||
- Create addon template
|
|
||||||
|
|
||||||
**Phase 3:**
|
|
||||||
- Build premium addons (WhatsApp, SMS)
|
|
||||||
- Marketplace listing
|
|
||||||
- Community addons
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Key Takeaway
|
|
||||||
|
|
||||||
**WooNooW Core = Framework + Email**
|
|
||||||
**Everything Else = Addons**
|
|
||||||
|
|
||||||
This keeps the core lean while providing unlimited extensibility for notification channels.
|
|
||||||
295
NOTIFICATION_SYSTEM.md
Normal file
295
NOTIFICATION_SYSTEM.md
Normal file
@@ -0,0 +1,295 @@
|
|||||||
|
# Notification System Documentation
|
||||||
|
|
||||||
|
**Status:** ✅ Complete & Fully Wired
|
||||||
|
**Last Updated:** November 15, 2025
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
WooNooW features a modern, flexible notification system that supports multiple channels (Email, Push, WhatsApp, Telegram, SMS) with customizable templates and markdown support.
|
||||||
|
|
||||||
|
### Key Features
|
||||||
|
- ✅ Multi-channel support (Email, Push, + Addons)
|
||||||
|
- ✅ Custom markdown templates with visual builder
|
||||||
|
- ✅ Variable system for dynamic content
|
||||||
|
- ✅ Global system toggle (WooNooW vs WooCommerce)
|
||||||
|
- ✅ Per-channel and per-event toggles
|
||||||
|
- ✅ Email customization (colors, logo, branding)
|
||||||
|
- ✅ Async email queue (prevents 30s timeout)
|
||||||
|
- ✅ Full backend wiring complete
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
### Structure
|
||||||
|
```
|
||||||
|
Notifications
|
||||||
|
├── Staff Notifications (toggle channels/events)
|
||||||
|
├── Customer Notifications (toggle channels/events)
|
||||||
|
├── Channel Configuration (global settings)
|
||||||
|
│ ├── Email (template + connection)
|
||||||
|
│ └── Push (template + connection)
|
||||||
|
└── Activity Log (coming soon)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Notification Flow
|
||||||
|
```
|
||||||
|
Event → EmailManager → Check System Mode → Check Channel Toggle
|
||||||
|
→ Check Event Toggle → EmailRenderer → Get Template → Replace Variables
|
||||||
|
→ Parse Markdown → Apply Branding → Queue via MailQueue → Send
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Markdown Syntax
|
||||||
|
|
||||||
|
### Cards
|
||||||
|
```markdown
|
||||||
|
[card:info]
|
||||||
|
Your content here
|
||||||
|
[/card]
|
||||||
|
|
||||||
|
[card:success]
|
||||||
|
Success message
|
||||||
|
[/card]
|
||||||
|
|
||||||
|
[card:warning]
|
||||||
|
Warning message
|
||||||
|
[/card]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Buttons
|
||||||
|
```markdown
|
||||||
|
[button:solid](https://example.com)
|
||||||
|
Click Me
|
||||||
|
[/button]
|
||||||
|
|
||||||
|
[button:outline](https://example.com)
|
||||||
|
Learn More
|
||||||
|
[/button]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Images
|
||||||
|
```markdown
|
||||||
|

|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Variables
|
||||||
|
|
||||||
|
### Order Variables
|
||||||
|
- `{order_number}` - Order number
|
||||||
|
- `{order_date}` - Order date
|
||||||
|
- `{order_total}` - Order total
|
||||||
|
- `{order_status}` - Order status
|
||||||
|
- `{order_items_table}` - Formatted table
|
||||||
|
- `{order_items_list}` - Formatted list
|
||||||
|
|
||||||
|
### Customer Variables
|
||||||
|
- `{customer_name}` - Customer full name
|
||||||
|
- `{customer_first_name}` - First name
|
||||||
|
- `{customer_last_name}` - Last name
|
||||||
|
- `{customer_email}` - Email address
|
||||||
|
|
||||||
|
### Store Variables
|
||||||
|
- `{store_name}` - Store name
|
||||||
|
- `{store_url}` - Store URL
|
||||||
|
- `{store_email}` - Store email
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Backend Integration
|
||||||
|
|
||||||
|
### API Endpoints
|
||||||
|
|
||||||
|
| Method | Endpoint | Purpose |
|
||||||
|
|--------|----------|---------|
|
||||||
|
| GET | `/notifications/system-mode` | Get current mode |
|
||||||
|
| POST | `/notifications/system-mode` | Switch mode |
|
||||||
|
| GET | `/notifications/channels` | Get all channels |
|
||||||
|
| POST | `/notifications/channels/toggle` | Toggle channel |
|
||||||
|
| GET | `/notifications/events` | Get all events |
|
||||||
|
| POST | `/notifications/events/update` | Update event |
|
||||||
|
| GET | `/notifications/templates/{id}/{ch}` | Get template |
|
||||||
|
| POST | `/notifications/templates` | Save template |
|
||||||
|
| GET | `/notifications/email-settings` | Get email customization |
|
||||||
|
| POST | `/notifications/email-settings` | Save email customization |
|
||||||
|
|
||||||
|
### Database Options
|
||||||
|
|
||||||
|
```php
|
||||||
|
// System mode
|
||||||
|
woonoow_notification_system_mode = 'woonoow' | 'woocommerce'
|
||||||
|
|
||||||
|
// Channel toggles
|
||||||
|
woonoow_email_notifications_enabled = true | false
|
||||||
|
woonoow_push_notifications_enabled = true | false
|
||||||
|
|
||||||
|
// Event settings
|
||||||
|
woonoow_notification_settings = [
|
||||||
|
'order_processing' => [
|
||||||
|
'channels' => [
|
||||||
|
'email' => ['enabled' => true, 'recipient' => 'customer']
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
// Templates
|
||||||
|
woonoow_notification_templates = [
|
||||||
|
'order_processing_email_customer' => [
|
||||||
|
'subject' => '...',
|
||||||
|
'body' => '...'
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
// Email customization
|
||||||
|
woonoow_email_settings = [
|
||||||
|
'primary_color' => '#7f54b3',
|
||||||
|
'logo_url' => '...',
|
||||||
|
...
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Email Queue System
|
||||||
|
|
||||||
|
### Purpose
|
||||||
|
Prevents 30-second timeout when sending emails via SMTP.
|
||||||
|
|
||||||
|
### Implementation
|
||||||
|
- **WooEmailOverride**: Intercepts `wp_mail()` calls
|
||||||
|
- **MailQueue**: Queues emails via Action Scheduler
|
||||||
|
- **Async Processing**: Emails sent in background
|
||||||
|
|
||||||
|
### Files
|
||||||
|
- `includes/Core/Mail/WooEmailOverride.php`
|
||||||
|
- `includes/Core/Mail/MailQueue.php`
|
||||||
|
|
||||||
|
### Initialization
|
||||||
|
```php
|
||||||
|
// In Bootstrap.php
|
||||||
|
MailQueue::init();
|
||||||
|
WooEmailOverride::init();
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Key Classes
|
||||||
|
|
||||||
|
### NotificationManager
|
||||||
|
**File:** `includes/Core/Notifications/NotificationManager.php`
|
||||||
|
|
||||||
|
- `should_send_notification()` - Validates all toggles
|
||||||
|
- `send()` - Main sending method
|
||||||
|
- `is_channel_enabled()` - Check global channel state
|
||||||
|
- `is_event_channel_enabled()` - Check per-event state
|
||||||
|
|
||||||
|
### EmailManager
|
||||||
|
**File:** `includes/Core/Notifications/EmailManager.php`
|
||||||
|
|
||||||
|
- `is_enabled()` - Check if WooNooW system active
|
||||||
|
- `disable_wc_emails()` - Disable WooCommerce emails
|
||||||
|
- Hooks into WooCommerce order status changes
|
||||||
|
|
||||||
|
### EmailRenderer
|
||||||
|
**File:** `includes/Core/Notifications/EmailRenderer.php`
|
||||||
|
|
||||||
|
- `render()` - Render email from template
|
||||||
|
- `replace_variables()` - Replace variables with data
|
||||||
|
- `parse_cards()` - Parse markdown cards
|
||||||
|
- Applies email customization
|
||||||
|
|
||||||
|
### TemplateProvider
|
||||||
|
**File:** `includes/Core/Notifications/TemplateProvider.php`
|
||||||
|
|
||||||
|
- `get_template()` - Get custom or default template
|
||||||
|
- `get_variables()` - Get available variables
|
||||||
|
- `get_default_template()` - Get default template
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Global System Toggle
|
||||||
|
|
||||||
|
### Purpose
|
||||||
|
Allow users to switch between WooNooW and WooCommerce notification systems.
|
||||||
|
|
||||||
|
### Modes
|
||||||
|
|
||||||
|
**WooNooW Mode** (default):
|
||||||
|
- Custom templates with markdown
|
||||||
|
- Multi-channel support
|
||||||
|
- Full customization
|
||||||
|
- WooCommerce emails disabled
|
||||||
|
|
||||||
|
**WooCommerce Mode**:
|
||||||
|
- Standard WooCommerce emails
|
||||||
|
- WooNooW notifications disabled
|
||||||
|
- For users who prefer classic system
|
||||||
|
|
||||||
|
### Implementation
|
||||||
|
```php
|
||||||
|
// Check mode
|
||||||
|
$mode = get_option('woonoow_notification_system_mode', 'woonoow');
|
||||||
|
|
||||||
|
// EmailManager respects mode
|
||||||
|
if (!EmailManager::is_enabled()) {
|
||||||
|
return; // Skip WooNooW notifications
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotificationManager checks mode
|
||||||
|
if ($system_mode !== 'woonoow') {
|
||||||
|
return false; // Use WooCommerce instead
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Q&A
|
||||||
|
|
||||||
|
### Q: Are templates saved and used when sending?
|
||||||
|
**A:** ✅ Yes. Templates saved via API are fetched by EmailRenderer and used when sending.
|
||||||
|
|
||||||
|
### Q: Are channel toggles respected?
|
||||||
|
**A:** ✅ Yes. NotificationManager checks both global and per-event toggles before sending.
|
||||||
|
|
||||||
|
### Q: Does the global system toggle work?
|
||||||
|
**A:** ✅ Yes. EmailManager and NotificationManager both check the mode before processing.
|
||||||
|
|
||||||
|
### Q: Is email sending async?
|
||||||
|
**A:** ✅ Yes. MailQueue queues emails via Action Scheduler to prevent timeouts.
|
||||||
|
|
||||||
|
### Q: Are variables replaced correctly?
|
||||||
|
**A:** ✅ Yes. EmailRenderer replaces all variables with actual data from orders/customers.
|
||||||
|
|
||||||
|
### Q: Does markdown parsing work?
|
||||||
|
**A:** ✅ Yes. Cards, buttons, and images are parsed correctly in both visual builder and email output.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Related Documentation
|
||||||
|
|
||||||
|
- **NEW_MARKDOWN_SYNTAX.md** - Markdown syntax reference
|
||||||
|
- **NOTIFICATION_SYSTEM_QA.md** - Q&A and backend status
|
||||||
|
- **BACKEND_WIRING_COMPLETE.md** - Backend integration details
|
||||||
|
- **CUSTOM_EMAIL_SYSTEM.md** - Email system architecture
|
||||||
|
- **FILTER_HOOKS_GUIDE.md** - Available hooks for customization
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Future Enhancements
|
||||||
|
|
||||||
|
### Planned Features
|
||||||
|
- Activity Log page
|
||||||
|
- WhatsApp addon
|
||||||
|
- Telegram addon
|
||||||
|
- SMS addon
|
||||||
|
- A/B testing for templates
|
||||||
|
- Scheduled notifications
|
||||||
|
- Customer notification preferences page
|
||||||
|
|
||||||
|
### Addon Development
|
||||||
|
See **ADDON_DEVELOPMENT_GUIDE.md** for creating custom notification channels.
|
||||||
@@ -1,201 +0,0 @@
|
|||||||
# Notification System - Q&A
|
|
||||||
|
|
||||||
## Questions & Answers
|
|
||||||
|
|
||||||
### 1. **Why no toggle for Email/Push in Customer Channels?**
|
|
||||||
|
|
||||||
**Answer**: ✅ **FIXED!** Added toggles to Customer Channels.
|
|
||||||
|
|
||||||
**Implementation**:
|
|
||||||
- Added `Switch` component to Email and Push channels
|
|
||||||
- Added mutation to toggle channel enable/disable
|
|
||||||
- When disabled, customers won't see these options in their account page
|
|
||||||
|
|
||||||
**User Flow**:
|
|
||||||
```
|
|
||||||
Admin disables Email → Customer account page hides email notification preferences
|
|
||||||
Admin disables Push → Customer account page hides push notification preferences
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 2. **Flexibility: Optional Channels & WooCommerce Default Email**
|
|
||||||
|
|
||||||
**Answer**: ✅ **Excellent idea!** Here's the proposed implementation:
|
|
||||||
|
|
||||||
#### **A. Make All Channels Optional**
|
|
||||||
- ✅ Staff channels: Already have toggles
|
|
||||||
- ✅ Customer channels: Now have toggles (just added)
|
|
||||||
- Each channel can be completely disabled
|
|
||||||
|
|
||||||
#### **B. Global WooNooW Notification Toggle**
|
|
||||||
|
|
||||||
**Proposed Location**: `/settings/notifications` (main page)
|
|
||||||
|
|
||||||
**New Card**:
|
|
||||||
```
|
|
||||||
┌─────────────────────────────────────────┐
|
|
||||||
│ 🔔 Notification System │
|
|
||||||
│ │
|
|
||||||
│ ○ Use WooNooW Notifications (default) │
|
|
||||||
│ Modern notification system with │
|
|
||||||
│ multiple channels and templates │
|
|
||||||
│ │
|
|
||||||
│ ○ Use WooCommerce Default Emails │
|
|
||||||
│ Classic WooCommerce email system │
|
|
||||||
│ (WooNooW notifications disabled) │
|
|
||||||
│ │
|
|
||||||
│ [Save Changes] │
|
|
||||||
└─────────────────────────────────────────┘
|
|
||||||
```
|
|
||||||
|
|
||||||
**Behavior**:
|
|
||||||
- **When WooNooW is active**: WooCommerce default emails are disabled
|
|
||||||
- **When WooCommerce default is active**: WooNooW notifications are disabled
|
|
||||||
- Only one system can be active at a time
|
|
||||||
|
|
||||||
**Implementation Plan**:
|
|
||||||
1. Add global setting: `woonoow_notification_system` (values: `woonoow` | `woocommerce`)
|
|
||||||
2. Hook into WooCommerce email system:
|
|
||||||
- If `woonoow`: Disable WC emails, enable WooNooW
|
|
||||||
- If `woocommerce`: Enable WC emails, disable WooNooW
|
|
||||||
3. Add migration helper to switch between systems
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### 3. **Backend Integration Status**
|
|
||||||
|
|
||||||
**Answer**: ⚠️ **Partially Wired**
|
|
||||||
|
|
||||||
#### **✅ Already Wired (Frontend → Backend)**:
|
|
||||||
1. **Channel Toggle**:
|
|
||||||
- Endpoint: `POST /notifications/channels/toggle`
|
|
||||||
- Payload: `{ channelId, enabled }`
|
|
||||||
- Used in: Staff/Customer Channels tabs
|
|
||||||
|
|
||||||
2. **Event Toggle**:
|
|
||||||
- Endpoint: `POST /notifications/events/update`
|
|
||||||
- Payload: `{ eventId, channelId, enabled, recipient }`
|
|
||||||
- Used in: Staff/Customer Events tabs
|
|
||||||
|
|
||||||
3. **Template Fetch**:
|
|
||||||
- Endpoint: `GET /notifications/templates/{eventId}/{channelId}?recipient={type}`
|
|
||||||
- Used in: EditTemplate page
|
|
||||||
|
|
||||||
4. **Template Save**:
|
|
||||||
- Endpoint: `POST /notifications/templates/save`
|
|
||||||
- Payload: `{ eventId, channelId, recipient, subject, body }`
|
|
||||||
- Used in: EditTemplate page
|
|
||||||
|
|
||||||
#### **❌ Not Yet Wired (Need Backend Implementation)**:
|
|
||||||
1. **Email Configuration**:
|
|
||||||
- Template Settings (colors, logo, branding)
|
|
||||||
- Connection Settings (SMTP override)
|
|
||||||
- **Status**: Frontend ready, backend needs implementation
|
|
||||||
|
|
||||||
2. **Push Configuration**:
|
|
||||||
- Template Settings (icon, badge, sound)
|
|
||||||
- Connection Settings (FCM/OneSignal)
|
|
||||||
- **Status**: Frontend ready, backend needs implementation
|
|
||||||
|
|
||||||
3. **Channel Configuration**:
|
|
||||||
- Global channel settings
|
|
||||||
- **Status**: Frontend ready, backend needs implementation
|
|
||||||
|
|
||||||
4. **Global Notification System Toggle**:
|
|
||||||
- Switch between WooNooW and WooCommerce
|
|
||||||
- **Status**: Not implemented (proposed above)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Backend TODO List
|
|
||||||
|
|
||||||
### Priority 1: Core Functionality
|
|
||||||
- [ ] Implement Email Configuration endpoints
|
|
||||||
- `GET /notifications/email-settings`
|
|
||||||
- `POST /notifications/email-settings/save`
|
|
||||||
- [ ] Implement Push Configuration endpoints
|
|
||||||
- `GET /notifications/push-settings`
|
|
||||||
- `POST /notifications/push-settings/save`
|
|
||||||
- [ ] Add global notification system toggle
|
|
||||||
- `GET /notifications/system-mode`
|
|
||||||
- `POST /notifications/system-mode/set`
|
|
||||||
|
|
||||||
### Priority 2: Integration
|
|
||||||
- [ ] Hook into WooCommerce email system
|
|
||||||
- Disable WC emails when WooNooW is active
|
|
||||||
- Re-enable WC emails when switched back
|
|
||||||
- [ ] Customer account page integration
|
|
||||||
- Show/hide notification preferences based on enabled channels
|
|
||||||
- Save customer notification preferences
|
|
||||||
|
|
||||||
### Priority 3: Enhancement
|
|
||||||
- [ ] Activity Log endpoints
|
|
||||||
- `GET /notifications/activity-log`
|
|
||||||
- Track sent notifications
|
|
||||||
- [ ] Addon system for channels
|
|
||||||
- WhatsApp, Telegram, SMS integration points
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Recommended Next Steps
|
|
||||||
|
|
||||||
1. **Add Global Toggle** (High Priority)
|
|
||||||
- Implement the WooNooW vs WooCommerce toggle
|
|
||||||
- This gives users ultimate flexibility
|
|
||||||
|
|
||||||
2. **Wire Email Configuration** (Medium Priority)
|
|
||||||
- Connect frontend to backend for email branding
|
|
||||||
|
|
||||||
3. **Wire Push Configuration** (Low Priority)
|
|
||||||
- Can be done later, push is less critical
|
|
||||||
|
|
||||||
4. **Customer Account Integration** (High Priority)
|
|
||||||
- Show notification preferences based on enabled channels
|
|
||||||
- Let customers opt-in/opt-out per channel
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Architecture Summary
|
|
||||||
|
|
||||||
```
|
|
||||||
Frontend (React)
|
|
||||||
├── Notifications Main Page
|
|
||||||
│ └── [NEW] Global System Toggle (WooNooW vs WooCommerce)
|
|
||||||
├── Staff Notifications
|
|
||||||
│ ├── Channels (toggle on/off) ✅ Wired
|
|
||||||
│ └── Events (toggle + template edit) ✅ Wired
|
|
||||||
├── Customer Notifications
|
|
||||||
│ ├── Channels (toggle on/off) ✅ Just Added
|
|
||||||
│ └── Events (toggle + template edit) ✅ Wired
|
|
||||||
└── Channel Configuration
|
|
||||||
├── Email Config ⚠️ Frontend ready, backend needed
|
|
||||||
├── Push Config ⚠️ Frontend ready, backend needed
|
|
||||||
└── Addons (future)
|
|
||||||
|
|
||||||
Backend (PHP)
|
|
||||||
├── NotificationsController ✅ Partially implemented
|
|
||||||
├── TemplateProvider ✅ Implemented
|
|
||||||
├── EventRegistry ✅ Implemented
|
|
||||||
└── [NEEDED] ConfigurationController
|
|
||||||
├── Email settings
|
|
||||||
├── Push settings
|
|
||||||
└── Global system toggle
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
**What's Working**:
|
|
||||||
- ✅ Channel enable/disable (Staff & Customer)
|
|
||||||
- ✅ Event enable/disable with template editing
|
|
||||||
- ✅ Template editor with markdown support
|
|
||||||
- ✅ Variable system
|
|
||||||
|
|
||||||
**What's Needed**:
|
|
||||||
- ⚠️ Backend for Email/Push configuration
|
|
||||||
- ⚠️ Global system toggle (WooNooW vs WooCommerce)
|
|
||||||
- ⚠️ Customer account page integration
|
|
||||||
|
|
||||||
**Recommendation**: Implement the global toggle first, as it provides the ultimate flexibility you want!
|
|
||||||
@@ -1,206 +0,0 @@
|
|||||||
# 🎯 THE REAL ROOT CAUSE - Recipient Type Missing from API
|
|
||||||
|
|
||||||
## 🔴 What You Discovered
|
|
||||||
|
|
||||||
You noticed the API URL was:
|
|
||||||
```
|
|
||||||
https://woonoow.local/wp-json/woonoow/v1/notifications/templates/order_placed/email
|
|
||||||
```
|
|
||||||
|
|
||||||
**NO `recipient` parameter!**
|
|
||||||
|
|
||||||
This means:
|
|
||||||
- Customer page → `order_placed` → Gets **STAFF** template ❌
|
|
||||||
- Staff page → `order_placed` → Gets **STAFF** template ✅
|
|
||||||
|
|
||||||
**The API couldn't distinguish between customer and staff templates!**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🔍 The Architecture Flaw
|
|
||||||
|
|
||||||
### **Before (BROKEN):**
|
|
||||||
```
|
|
||||||
URL Format: /templates/{event_id}/{channel_id}
|
|
||||||
Storage Key: {event_id}_{channel_id}
|
|
||||||
|
|
||||||
Problem: Same key for both customer AND staff!
|
|
||||||
- order_placed_email → STAFF template
|
|
||||||
- order_placed_email → CUSTOMER template (OVERWRITTEN!)
|
|
||||||
```
|
|
||||||
|
|
||||||
### **After (FIXED):**
|
|
||||||
```
|
|
||||||
URL Format: /templates/{event_id}/{channel_id}?recipient={recipient_type}
|
|
||||||
Storage Key: {recipient_type}_{event_id}_{channel_id}
|
|
||||||
|
|
||||||
Solution: Unique keys for each recipient!
|
|
||||||
- staff_order_placed_email → STAFF template ✅
|
|
||||||
- customer_order_placed_email → CUSTOMER template ✅
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📝 All Changes Made
|
|
||||||
|
|
||||||
### **1. Frontend - Templates.tsx**
|
|
||||||
**File:** `admin-spa/src/routes/Settings/Notifications/Templates.tsx`
|
|
||||||
**Line:** 63
|
|
||||||
**Change:** Pass `recipient` parameter when navigating to editor
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// BEFORE:
|
|
||||||
navigate(`/settings/notifications/edit-template?event=${event.id}&channel=${channel.id}`);
|
|
||||||
|
|
||||||
// AFTER:
|
|
||||||
navigate(`/settings/notifications/edit-template?event=${event.id}&channel=${channel.id}&recipient=${recipientType}`);
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **2. Frontend - EditTemplate.tsx**
|
|
||||||
**File:** `admin-spa/src/routes/Settings/Notifications/EditTemplate.tsx`
|
|
||||||
**Lines:** 34, 55, 141, 159
|
|
||||||
**Changes:**
|
|
||||||
1. Read `recipient` from URL
|
|
||||||
2. Pass to API GET request
|
|
||||||
3. Pass to API PUT request
|
|
||||||
4. Pass to API DELETE request
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Read recipient type
|
|
||||||
const recipientType = searchParams.get('recipient') || 'customer';
|
|
||||||
|
|
||||||
// Fetch template WITH recipient
|
|
||||||
const response = await api.get(`/notifications/templates/${eventId}/${channelId}?recipient=${recipientType}`);
|
|
||||||
|
|
||||||
// Save template WITH recipient
|
|
||||||
await api.put(`/notifications/templates/${eventId}/${channelId}?recipient=${recipientType}`, {...});
|
|
||||||
|
|
||||||
// Delete template WITH recipient
|
|
||||||
await api.del(`/notifications/templates/${eventId}/${channelId}?recipient=${recipientType}`);
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **3. Backend - NotificationsController.php**
|
|
||||||
**File:** `includes/Api/NotificationsController.php`
|
|
||||||
**Lines:** 587, 589, 638, 649, 674, 676
|
|
||||||
**Changes:** Accept `recipient` parameter and pass to TemplateProvider
|
|
||||||
|
|
||||||
```php
|
|
||||||
// Get template
|
|
||||||
$recipient_type = $request->get_param('recipient') ?? 'customer';
|
|
||||||
$template = TemplateProvider::get_template($event_id, $channel_id, $recipient_type);
|
|
||||||
|
|
||||||
// Save template
|
|
||||||
$recipient_type = $request->get_param('recipient') ?? 'customer';
|
|
||||||
$result = TemplateProvider::save_template($event_id, $channel_id, $template, $recipient_type);
|
|
||||||
|
|
||||||
// Delete template
|
|
||||||
$recipient_type = $request->get_param('recipient') ?? 'customer';
|
|
||||||
TemplateProvider::delete_template($event_id, $channel_id, $recipient_type);
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
### **4. Backend - TemplateProvider.php**
|
|
||||||
**File:** `includes/Core/Notifications/TemplateProvider.php`
|
|
||||||
**Lines:** 41, 44, 64, 67, 90, 93, 154
|
|
||||||
**Changes:** Use `{recipient_type}_{event_id}_{channel_id}` as storage key
|
|
||||||
|
|
||||||
```php
|
|
||||||
// Get template
|
|
||||||
public static function get_template($event_id, $channel_id, $recipient_type = 'customer') {
|
|
||||||
$key = "{$recipient_type}_{$event_id}_{channel_id}";
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
// Save template
|
|
||||||
public static function save_template($event_id, $channel_id, $template, $recipient_type = 'customer') {
|
|
||||||
$key = "{$recipient_type}_{$event_id}_{channel_id}";
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
// Delete template
|
|
||||||
public static function delete_template($event_id, $channel_id, $recipient_type = 'customer') {
|
|
||||||
$key = "{$recipient_type}_{$event_id}_{channel_id}";
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
// Default templates
|
|
||||||
$templates["{$recipient_type}_{$event_id}_email"] = [...];
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 Why This Fixes Everything
|
|
||||||
|
|
||||||
### **Issue #1: Customer showing 7 templates instead of 9**
|
|
||||||
**Root Cause:** API was fetching staff templates for customer page
|
|
||||||
**Fix:** Now API knows to fetch customer templates when on customer page
|
|
||||||
|
|
||||||
### **Issue #2: Loading staff template for customer event**
|
|
||||||
**Root Cause:** Same storage key for both staff and customer
|
|
||||||
**Fix:** Unique keys: `staff_order_placed_email` vs `customer_order_placed_email`
|
|
||||||
|
|
||||||
### **Issue #3: Saving overwrites wrong template**
|
|
||||||
**Root Cause:** Saving to same key regardless of recipient
|
|
||||||
**Fix:** Saves to correct recipient-specific key
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📊 Data Flow (Now Correct!)
|
|
||||||
|
|
||||||
### **Customer Page → Order Placed:**
|
|
||||||
```
|
|
||||||
1. User clicks "Edit" on Customer Notifications page
|
|
||||||
2. URL: /edit-template?event=order_placed&channel=email&recipient=customer
|
|
||||||
3. API: GET /templates/order_placed/email?recipient=customer
|
|
||||||
4. Key: customer_order_placed_email
|
|
||||||
5. Returns: CUSTOMER template ✅
|
|
||||||
```
|
|
||||||
|
|
||||||
### **Staff Page → Order Placed:**
|
|
||||||
```
|
|
||||||
1. User clicks "Edit" on Staff Notifications page
|
|
||||||
2. URL: /edit-template?event=order_placed&channel=email&recipient=staff
|
|
||||||
3. API: GET /templates/order_placed/email?recipient=staff
|
|
||||||
4. Key: staff_order_placed_email
|
|
||||||
5. Returns: STAFF template ✅
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🧪 Testing Steps
|
|
||||||
|
|
||||||
1. **Stop dev server:** Ctrl+C
|
|
||||||
2. **Restart:** `npm run dev`
|
|
||||||
3. **Hard refresh:** Cmd+Shift+R
|
|
||||||
4. **Test Customer Page:**
|
|
||||||
- Go to Customer Notifications
|
|
||||||
- Click "Order Placed" → Should show customer template
|
|
||||||
- Subject should be customer-facing
|
|
||||||
5. **Test Staff Page:**
|
|
||||||
- Go to Staff Notifications
|
|
||||||
- Click "Order Placed" → Should show staff template
|
|
||||||
- Subject should be staff-facing
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎉 Summary
|
|
||||||
|
|
||||||
**The Problem:** API had no way to distinguish between customer and staff templates
|
|
||||||
|
|
||||||
**The Solution:**
|
|
||||||
1. Pass `recipient` parameter in URL
|
|
||||||
2. Use `{recipient_type}_{event_id}_{channel_id}` as storage key
|
|
||||||
3. Update all API calls to include recipient type
|
|
||||||
|
|
||||||
**Files Changed:**
|
|
||||||
- ✅ Templates.tsx (pass recipient when navigating)
|
|
||||||
- ✅ EditTemplate.tsx (read recipient, pass to API)
|
|
||||||
- ✅ NotificationsController.php (accept recipient parameter)
|
|
||||||
- ✅ TemplateProvider.php (use recipient in storage keys)
|
|
||||||
|
|
||||||
**Result:** Customer and staff templates are now completely separate! 🎊
|
|
||||||
@@ -1,162 +0,0 @@
|
|||||||
# Single Source of Truth - Event Registry
|
|
||||||
|
|
||||||
## Problem Solved
|
|
||||||
|
|
||||||
Previously, events were hardcoded in multiple places:
|
|
||||||
- ❌ `NotificationsController.php` - hardcoded 9 events
|
|
||||||
- ❌ `TemplateProvider.php` - hardcoded 9 events
|
|
||||||
- ❌ `DefaultTemplates.php` - had 15 templates (8 customer + 7 staff)
|
|
||||||
|
|
||||||
**Result:** Mismatches, confusion, missing templates
|
|
||||||
|
|
||||||
## Solution: EventRegistry
|
|
||||||
|
|
||||||
Created `/includes/Core/Notifications/EventRegistry.php` as the **SINGLE SOURCE OF TRUTH**.
|
|
||||||
|
|
||||||
### How It Works
|
|
||||||
|
|
||||||
```php
|
|
||||||
// Get all events
|
|
||||||
$events = EventRegistry::get_all_events();
|
|
||||||
|
|
||||||
// Get by recipient
|
|
||||||
$staff_events = EventRegistry::get_events_by_recipient('staff');
|
|
||||||
$customer_events = EventRegistry::get_events_by_recipient('customer');
|
|
||||||
|
|
||||||
// Get by category
|
|
||||||
$order_events = EventRegistry::get_events_by_category('orders');
|
|
||||||
|
|
||||||
// Check if exists
|
|
||||||
if (EventRegistry::event_exists('order_placed', 'staff')) {
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Current Event List
|
|
||||||
|
|
||||||
**Staff Events (7):**
|
|
||||||
1. `order_placed` - New order notification
|
|
||||||
2. `order_processing` - Order confirmed, ready to process
|
|
||||||
3. `order_shipped` - Order shipped
|
|
||||||
4. `order_completed` - Order completed
|
|
||||||
5. `order_cancelled` - Order cancelled
|
|
||||||
6. `payment_received` - Payment confirmed
|
|
||||||
7. `payment_failed` - Payment failed
|
|
||||||
|
|
||||||
**Customer Events (8):**
|
|
||||||
1. `order_placed` - Order placed confirmation
|
|
||||||
2. `order_processing` - Order being processed
|
|
||||||
3. `order_shipped` - Order shipped with tracking
|
|
||||||
4. `order_completed` - Order delivered
|
|
||||||
5. `order_cancelled` - Order cancelled
|
|
||||||
6. `payment_received` - Payment confirmed
|
|
||||||
7. `payment_failed` - Payment failed, retry
|
|
||||||
8. `new_customer` - Welcome email
|
|
||||||
|
|
||||||
**Total: 15 events** (7 staff + 8 customer)
|
|
||||||
|
|
||||||
### Filter Hook
|
|
||||||
|
|
||||||
```php
|
|
||||||
add_filter('woonoow_notification_events_registry', function($events) {
|
|
||||||
// Add custom event
|
|
||||||
$events['custom_event'] = [
|
|
||||||
'id' => 'custom_event',
|
|
||||||
'label' => 'Custom Event',
|
|
||||||
'description' => 'My custom notification',
|
|
||||||
'category' => 'custom',
|
|
||||||
'recipient_type' => 'customer',
|
|
||||||
'wc_email' => '',
|
|
||||||
'enabled' => true,
|
|
||||||
];
|
|
||||||
|
|
||||||
return $events;
|
|
||||||
});
|
|
||||||
```
|
|
||||||
|
|
||||||
## Components Updated
|
|
||||||
|
|
||||||
### 1. NotificationsController.php
|
|
||||||
```php
|
|
||||||
// OLD - Hardcoded
|
|
||||||
$events = [
|
|
||||||
'orders' => [
|
|
||||||
['id' => 'order_placed', ...],
|
|
||||||
// ... 100+ lines
|
|
||||||
]
|
|
||||||
];
|
|
||||||
|
|
||||||
// NEW - Uses Registry
|
|
||||||
$all_events = EventRegistry::get_all_events();
|
|
||||||
foreach ($all_events as $event) {
|
|
||||||
// Group by category
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 2. TemplateProvider.php
|
|
||||||
```php
|
|
||||||
// OLD - Hardcoded
|
|
||||||
$events = [
|
|
||||||
'order_placed' => 'staff',
|
|
||||||
'order_processing' => 'customer',
|
|
||||||
// ...
|
|
||||||
];
|
|
||||||
|
|
||||||
// NEW - Uses Registry
|
|
||||||
$all_events = EventRegistry::get_all_events();
|
|
||||||
foreach ($all_events as $event) {
|
|
||||||
$event_id = $event['id'];
|
|
||||||
$recipient_type = $event['recipient_type'];
|
|
||||||
// Generate templates
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. DefaultTemplates.php
|
|
||||||
**No changes needed** - Already has all 15 templates matching the registry!
|
|
||||||
|
|
||||||
## Benefits
|
|
||||||
|
|
||||||
✅ **Single source of truth** - One place to add/remove events
|
|
||||||
✅ **No hardcoding** - All components query the registry
|
|
||||||
✅ **Extensible** - Filter hook for custom events
|
|
||||||
✅ **Type-safe** - Consistent event structure
|
|
||||||
✅ **No mismatches** - Events and templates always aligned
|
|
||||||
✅ **Easy maintenance** - Add event once, works everywhere
|
|
||||||
|
|
||||||
## Adding New Events
|
|
||||||
|
|
||||||
1. **Add to EventRegistry.php:**
|
|
||||||
```php
|
|
||||||
'low_stock' => [
|
|
||||||
'id' => 'low_stock',
|
|
||||||
'label' => __('Low Stock Alert', 'woonoow'),
|
|
||||||
'description' => __('When product stock is low', 'woonoow'),
|
|
||||||
'category' => 'products',
|
|
||||||
'recipient_type' => 'staff',
|
|
||||||
'wc_email' => 'low_stock',
|
|
||||||
'enabled' => true,
|
|
||||||
],
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Add template to DefaultTemplates.php:**
|
|
||||||
```php
|
|
||||||
'staff' => [
|
|
||||||
// ...
|
|
||||||
'low_stock' => self::staff_low_stock(),
|
|
||||||
],
|
|
||||||
|
|
||||||
private static function staff_low_stock() {
|
|
||||||
return '[card type="warning"]...';
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Done!** API and UI automatically show the new event.
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
After refresh:
|
|
||||||
- ✅ Events API returns 15 events (7 staff + 8 customer)
|
|
||||||
- ✅ Templates API returns 15 templates
|
|
||||||
- ✅ UI shows correct counts
|
|
||||||
- ✅ All templates load without errors
|
|
||||||
- ✅ No hardcoded lists anywhere
|
|
||||||
@@ -1,226 +0,0 @@
|
|||||||
# ✅ ALL TEMPLATES POLISHED! 🚀
|
|
||||||
|
|
||||||
## COMPLETE! All 17 Templates Updated!
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## What Was Done
|
|
||||||
|
|
||||||
### ✅ 1. Added Proper Headings
|
|
||||||
- **Hero/Success/Warning cards**: `##` (H2) for main titles
|
|
||||||
- **Welcome card**: `#` (H1) for special welcome
|
|
||||||
- All first lines in important cards now have headings
|
|
||||||
|
|
||||||
### ✅ 2. Clean Footers
|
|
||||||
- **Customer templates**: Wrapped support text in `[card type="basic"]`
|
|
||||||
- **Staff templates**: Removed footers entirely (no support contact needed)
|
|
||||||
- **All templates**: Removed `© {current_year} {site_name}` (handled by global footer)
|
|
||||||
|
|
||||||
### ✅ 3. Removed Separators
|
|
||||||
- Removed all `---` horizontal rules before footers
|
|
||||||
- Cleaner, more modern look
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Templates Updated (17 Total)
|
|
||||||
|
|
||||||
### Customer Templates (9):
|
|
||||||
1. ✅ **customer_order_placed** - `## Thank you for your order, {customer_name}!`
|
|
||||||
2. ✅ **customer_order_confirmed** - `## Great news, {customer_name}!`
|
|
||||||
3. ✅ **customer_order_shipped** - `## Your order #{order_number} has shipped!`
|
|
||||||
4. ✅ **customer_order_completed** - `## Your order #{order_number} has arrived!`
|
|
||||||
5. ✅ **customer_order_cancelled** - `## Your order #{order_number} has been cancelled.`
|
|
||||||
6. ✅ **customer_payment_received** - `## Payment confirmed!`
|
|
||||||
7. ✅ **customer_payment_failed** - `## Payment could not be processed`
|
|
||||||
8. ✅ **customer_registered** - `# Welcome to {site_name}, {customer_name}!`
|
|
||||||
9. ✅ **customer_vip_upgraded** - `## Congratulations, {customer_name}!`
|
|
||||||
|
|
||||||
### Staff Templates (8):
|
|
||||||
10. ✅ **staff_order_placed** - `# New order received!`
|
|
||||||
11. ✅ **staff_order_confirmed** - `## Order confirmed and ready to process`
|
|
||||||
12. ✅ **staff_order_shipped** - `## Order shipped`
|
|
||||||
13. ✅ **staff_order_completed** - `## Order completed`
|
|
||||||
14. ✅ **staff_order_cancelled** - `## Order cancelled`
|
|
||||||
15. ✅ **staff_payment_received** - `## Payment received`
|
|
||||||
16. ✅ **staff_payment_failed** - `## Payment failed`
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Before vs After Examples
|
|
||||||
|
|
||||||
### Customer Template:
|
|
||||||
```markdown
|
|
||||||
// BEFORE:
|
|
||||||
[card type="hero"]
|
|
||||||
|
|
||||||
Thank you for your order, {customer_name}!
|
|
||||||
|
|
||||||
We've received your order...
|
|
||||||
[/card]
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
Need help? Contact us: {support_email}
|
|
||||||
© {current_year} {site_name}
|
|
||||||
|
|
||||||
// AFTER:
|
|
||||||
[card type="hero"]
|
|
||||||
|
|
||||||
## Thank you for your order, {customer_name}!
|
|
||||||
|
|
||||||
We've received your order...
|
|
||||||
[/card]
|
|
||||||
|
|
||||||
[card type="basic"]
|
|
||||||
|
|
||||||
Need help? Contact us: {support_email}
|
|
||||||
|
|
||||||
[/card]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Staff Template:
|
|
||||||
```markdown
|
|
||||||
// BEFORE:
|
|
||||||
[card type="hero"]
|
|
||||||
|
|
||||||
New order received!
|
|
||||||
|
|
||||||
A customer has placed...
|
|
||||||
[/card]
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
WooNooW Order Management
|
|
||||||
© {current_year} {site_name}
|
|
||||||
|
|
||||||
// AFTER:
|
|
||||||
[card type="hero"]
|
|
||||||
|
|
||||||
# New order received!
|
|
||||||
|
|
||||||
A customer has placed...
|
|
||||||
[/card]
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Heading Hierarchy
|
|
||||||
|
|
||||||
| Card Type | Heading Level | Example |
|
|
||||||
|-----------|---------------|---------|
|
|
||||||
| Hero (Customer) | `##` (H2) | `## Thank you for your order!` |
|
|
||||||
| Hero (Staff) | `#` (H1) | `# New order received!` |
|
|
||||||
| Success | `##` (H2) | `## Great news!` |
|
|
||||||
| Warning | `##` (H2) | `## Payment could not be processed` |
|
|
||||||
| Welcome | `#` (H1) | `# Welcome to {site_name}!` |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Footer Strategy
|
|
||||||
|
|
||||||
### Customer Templates:
|
|
||||||
```markdown
|
|
||||||
[card type="basic"]
|
|
||||||
|
|
||||||
Need help? Contact {support_email}
|
|
||||||
|
|
||||||
[/card]
|
|
||||||
```
|
|
||||||
- Plain text section
|
|
||||||
- No styling
|
|
||||||
- Support contact included
|
|
||||||
- No copyright (global footer handles it)
|
|
||||||
|
|
||||||
### Staff Templates:
|
|
||||||
```markdown
|
|
||||||
(No footer)
|
|
||||||
```
|
|
||||||
- Staff doesn't need support contact
|
|
||||||
- Cleaner, more professional
|
|
||||||
- Focus on action items
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Benefits
|
|
||||||
|
|
||||||
### ✅ Better Typography:
|
|
||||||
- Clear visual hierarchy
|
|
||||||
- Proper heading sizes
|
|
||||||
- More professional appearance
|
|
||||||
|
|
||||||
### ✅ Cleaner Structure:
|
|
||||||
- No redundant separators
|
|
||||||
- Consistent footer pattern
|
|
||||||
- Better readability
|
|
||||||
|
|
||||||
### ✅ No Content Loss:
|
|
||||||
- All content wrapped in cards
|
|
||||||
- Basic card type for plain text
|
|
||||||
- Everything preserved
|
|
||||||
|
|
||||||
### ✅ Mobile Friendly:
|
|
||||||
- Headings scale properly
|
|
||||||
- Better responsive design
|
|
||||||
- Easier to scan
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## What's Next
|
|
||||||
|
|
||||||
### Test It! 🧪
|
|
||||||
|
|
||||||
1. **Hard refresh** browser (Cmd+Shift+R)
|
|
||||||
2. Go to **Settings → Notifications → Staff/Customer → Templates**
|
|
||||||
3. Open any template
|
|
||||||
4. ✅ See proper headings
|
|
||||||
5. ✅ See clean footers
|
|
||||||
6. ✅ No copyright lines
|
|
||||||
7. ✅ All content preserved
|
|
||||||
|
|
||||||
### Expected Results:
|
|
||||||
|
|
||||||
**Visual Builder:**
|
|
||||||
- ✅ All cards display
|
|
||||||
- ✅ Headings are bold and larger
|
|
||||||
- ✅ Footer in basic card (customer) or no footer (staff)
|
|
||||||
|
|
||||||
**Preview:**
|
|
||||||
- ✅ Beautiful typography
|
|
||||||
- ✅ Clear hierarchy
|
|
||||||
- ✅ Professional appearance
|
|
||||||
- ✅ Proper spacing
|
|
||||||
|
|
||||||
**Code Mode:**
|
|
||||||
- ✅ Clean markdown
|
|
||||||
- ✅ Proper heading syntax
|
|
||||||
- ✅ Basic card for footers
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Summary
|
|
||||||
|
|
||||||
| Item | Status |
|
|
||||||
|------|--------|
|
|
||||||
| Headings added | ✅ 17/17 |
|
|
||||||
| Footers cleaned | ✅ 17/17 |
|
|
||||||
| Copyright removed | ✅ 17/17 |
|
|
||||||
| Basic cards added | ✅ 9/9 customer |
|
|
||||||
| Staff footers removed | ✅ 8/8 staff |
|
|
||||||
| Newline parsing | ✅ Fixed |
|
|
||||||
| Basic card type | ✅ Added |
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Files Modified
|
|
||||||
|
|
||||||
1. ✅ `markdown-utils.ts` - Fixed newline parsing
|
|
||||||
2. ✅ `types.ts` - Added 'basic' card type
|
|
||||||
3. ✅ `EmailBuilder.tsx` - Added basic to selector
|
|
||||||
4. ✅ `EditTemplate.tsx` - Added CSS for basic cards
|
|
||||||
5. ✅ `DefaultTemplates.php` - **ALL 17 templates polished!**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**🎉 COMPLETE! All templates are now polished and production-ready! 🚀**
|
|
||||||
|
|
||||||
**Time to test and ship!**
|
|
||||||
@@ -1,128 +0,0 @@
|
|||||||
# Template Source of Truth
|
|
||||||
|
|
||||||
## Single Source of Truth: `/includes/Email/DefaultTemplates.php`
|
|
||||||
|
|
||||||
This file contains **clean markdown templates** without HTML tags inside shortcodes.
|
|
||||||
|
|
||||||
### Structure
|
|
||||||
|
|
||||||
```php
|
|
||||||
namespace WooNooW\Email;
|
|
||||||
|
|
||||||
class DefaultTemplates {
|
|
||||||
public static function get_all_templates() {
|
|
||||||
return [
|
|
||||||
'customer' => [
|
|
||||||
'order_placed' => '...',
|
|
||||||
'order_confirmed' => '...',
|
|
||||||
'order_shipped' => '...',
|
|
||||||
'order_completed' => '...',
|
|
||||||
'order_cancelled' => '...',
|
|
||||||
'payment_received' => '...',
|
|
||||||
'payment_failed' => '...',
|
|
||||||
'registered' => '...',
|
|
||||||
'vip_upgraded' => '...',
|
|
||||||
],
|
|
||||||
'staff' => [
|
|
||||||
'order_placed' => '...',
|
|
||||||
'order_confirmed' => '...',
|
|
||||||
'order_shipped' => '...',
|
|
||||||
'order_completed' => '...',
|
|
||||||
'order_cancelled' => '...',
|
|
||||||
'payment_received' => '...',
|
|
||||||
'payment_failed' => '...',
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
public static function get_default_subject($recipient, $event) {
|
|
||||||
// Returns subject string
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Template Format
|
|
||||||
|
|
||||||
Templates use **clean markdown** inside `[card]` shortcodes:
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
[card type="hero"]
|
|
||||||
|
|
||||||
## Thank you for your order, {customer_name}!
|
|
||||||
|
|
||||||
We've received your order and will begin processing it right away.
|
|
||||||
[/card]
|
|
||||||
|
|
||||||
[card]
|
|
||||||
|
|
||||||
**Order Number:** #{order_number}
|
|
||||||
**Order Date:** {order_date}
|
|
||||||
**Order Total:** {order_total}
|
|
||||||
|
|
||||||
[/card]
|
|
||||||
|
|
||||||
[button url="{order_url}"]View Order Details[/button]
|
|
||||||
```
|
|
||||||
|
|
||||||
**NOT** HTML like this:
|
|
||||||
```html
|
|
||||||
[card type="hero"]
|
|
||||||
<h1>Thank you for your order, {customer_name}!</h1>
|
|
||||||
<p>We've received your order...</p>
|
|
||||||
[/card]
|
|
||||||
```
|
|
||||||
|
|
||||||
## How It's Used
|
|
||||||
|
|
||||||
### TemplateProvider.php
|
|
||||||
|
|
||||||
`/includes/Core/Notifications/TemplateProvider.php` uses the Email templates:
|
|
||||||
|
|
||||||
```php
|
|
||||||
use WooNooW\Email\DefaultTemplates as EmailDefaultTemplates;
|
|
||||||
|
|
||||||
// Get all templates
|
|
||||||
$allEmailTemplates = EmailDefaultTemplates::get_all_templates();
|
|
||||||
|
|
||||||
// Get specific template
|
|
||||||
$body = $allEmailTemplates[$recipient_type][$template_name];
|
|
||||||
$subject = EmailDefaultTemplates::get_default_subject($recipient_type, $template_name);
|
|
||||||
```
|
|
||||||
|
|
||||||
### Event ID Mapping
|
|
||||||
|
|
||||||
API event IDs are mapped to template names:
|
|
||||||
|
|
||||||
| API Event ID | Template Name |
|
|
||||||
|-------------|---------------|
|
|
||||||
| `order_processing` | `order_confirmed` |
|
|
||||||
| `new_customer` | `registered` |
|
|
||||||
| Others | Same name |
|
|
||||||
|
|
||||||
## Deprecated Files
|
|
||||||
|
|
||||||
### `/includes/Core/Notifications/DefaultEmailTemplates.php` ❌
|
|
||||||
|
|
||||||
**DO NOT USE** - This file contains old templates with HTML tags inside shortcodes.
|
|
||||||
|
|
||||||
It's kept for backwards compatibility only and is marked as deprecated.
|
|
||||||
|
|
||||||
## Frontend Conversion
|
|
||||||
|
|
||||||
When templates are loaded in the editor:
|
|
||||||
|
|
||||||
1. **Database** stores HTML (for backwards compatibility)
|
|
||||||
2. **converter.ts** converts HTML to clean markdown using `convertHtmlToMarkdown()`
|
|
||||||
3. **CodeEditor** displays clean markdown
|
|
||||||
4. **User edits** in markdown
|
|
||||||
5. **Saves** back as HTML (via blocks → HTML conversion)
|
|
||||||
|
|
||||||
This ensures smooth editing experience while maintaining compatibility.
|
|
||||||
|
|
||||||
## Benefits
|
|
||||||
|
|
||||||
✅ **Clean markdown editing** - No HTML tags in markdown mode
|
|
||||||
✅ **Single source of truth** - One place to update templates
|
|
||||||
✅ **Better UX** - Markdown toolbar and syntax highlighting
|
|
||||||
✅ **Mobile-friendly** - Easy to type on any device
|
|
||||||
✅ **Maintainable** - Clear separation of concerns
|
|
||||||
@@ -1,259 +0,0 @@
|
|||||||
# Template Update Script
|
|
||||||
|
|
||||||
## Changes to Make in DefaultTemplates.php
|
|
||||||
|
|
||||||
For ALL templates, replace the footer pattern:
|
|
||||||
|
|
||||||
### Pattern to Find:
|
|
||||||
```
|
|
||||||
---
|
|
||||||
|
|
||||||
[Any text with {support_email} or similar]
|
|
||||||
© {current_year} {site_name}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Replace With:
|
|
||||||
```
|
|
||||||
[card type="basic"]
|
|
||||||
|
|
||||||
[Same text with {support_email}]
|
|
||||||
|
|
||||||
[/card]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Remove:
|
|
||||||
- All instances of `© {current_year} {site_name}` (already in global footer)
|
|
||||||
- All instances of standalone `---` before footer text
|
|
||||||
|
|
||||||
## Specific Updates:
|
|
||||||
|
|
||||||
### Customer Templates:
|
|
||||||
|
|
||||||
1. **customer_order_placed** (line 138-141):
|
|
||||||
```php
|
|
||||||
// OLD:
|
|
||||||
---
|
|
||||||
|
|
||||||
Need help? Contact us: {support_email}
|
|
||||||
© {current_year} {site_name}';
|
|
||||||
|
|
||||||
// NEW:
|
|
||||||
[card type="basic"]
|
|
||||||
|
|
||||||
Need help? Contact us: {support_email}
|
|
||||||
|
|
||||||
[/card]';
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **customer_order_confirmed** (line 180-183):
|
|
||||||
```php
|
|
||||||
// OLD:
|
|
||||||
---
|
|
||||||
|
|
||||||
Questions? We\'re here to help: {support_email}
|
|
||||||
© {current_year} {site_name}';
|
|
||||||
|
|
||||||
// NEW:
|
|
||||||
[card type="basic"]
|
|
||||||
|
|
||||||
Questions? We\'re here to help: {support_email}
|
|
||||||
|
|
||||||
[/card]';
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **customer_order_shipped** (line 222-225):
|
|
||||||
```php
|
|
||||||
// OLD:
|
|
||||||
---
|
|
||||||
|
|
||||||
Need assistance? Contact {support_email}
|
|
||||||
© {current_year} {site_name}';
|
|
||||||
|
|
||||||
// NEW:
|
|
||||||
[card type="basic"]
|
|
||||||
|
|
||||||
Need assistance? Contact {support_email}
|
|
||||||
|
|
||||||
[/card]';
|
|
||||||
```
|
|
||||||
|
|
||||||
4. **customer_order_completed** (line 262-267):
|
|
||||||
```php
|
|
||||||
// OLD:
|
|
||||||
---
|
|
||||||
|
|
||||||
Questions or issues with your order? We\'re here to help.
|
|
||||||
{support_email}
|
|
||||||
|
|
||||||
© {current_year} {site_name}';
|
|
||||||
|
|
||||||
// NEW:
|
|
||||||
[card type="basic"]
|
|
||||||
|
|
||||||
Questions or issues with your order? We\'re here to help.
|
|
||||||
|
|
||||||
Contact: {support_email}
|
|
||||||
|
|
||||||
[/card]';
|
|
||||||
```
|
|
||||||
|
|
||||||
5. **customer_order_cancelled** (line 309-311):
|
|
||||||
```php
|
|
||||||
// OLD:
|
|
||||||
---
|
|
||||||
|
|
||||||
© {current_year} {site_name}';
|
|
||||||
|
|
||||||
// NEW:
|
|
||||||
';
|
|
||||||
// (Just remove the footer entirely - no support text here)
|
|
||||||
```
|
|
||||||
|
|
||||||
6. **customer_payment_received** (line 349-351):
|
|
||||||
```php
|
|
||||||
// OLD:
|
|
||||||
---
|
|
||||||
|
|
||||||
© {current_year} {site_name}';
|
|
||||||
|
|
||||||
// NEW:
|
|
||||||
';
|
|
||||||
// (Just remove)
|
|
||||||
```
|
|
||||||
|
|
||||||
7. **customer_payment_failed** (line 398-400):
|
|
||||||
```php
|
|
||||||
// OLD:
|
|
||||||
---
|
|
||||||
|
|
||||||
© {current_year} {site_name}';
|
|
||||||
|
|
||||||
// NEW:
|
|
||||||
';
|
|
||||||
// (Already has support text in card, just remove footer)
|
|
||||||
```
|
|
||||||
|
|
||||||
8. **customer_registered** (line 436-439):
|
|
||||||
```php
|
|
||||||
// OLD:
|
|
||||||
---
|
|
||||||
|
|
||||||
Need help? Contact {support_email}
|
|
||||||
© {current_year} {site_name}';
|
|
||||||
|
|
||||||
// NEW:
|
|
||||||
[card type="basic"]
|
|
||||||
|
|
||||||
Need help? Contact {support_email}
|
|
||||||
|
|
||||||
[/card]';
|
|
||||||
```
|
|
||||||
|
|
||||||
9. **customer_vip_upgraded** (line 473-476):
|
|
||||||
```php
|
|
||||||
// OLD:
|
|
||||||
---
|
|
||||||
|
|
||||||
Questions? {support_email}
|
|
||||||
© {current_year} {site_name}';
|
|
||||||
|
|
||||||
// NEW:
|
|
||||||
[card type="basic"]
|
|
||||||
|
|
||||||
Questions? {support_email}
|
|
||||||
|
|
||||||
[/card]';
|
|
||||||
```
|
|
||||||
|
|
||||||
### Staff Templates:
|
|
||||||
|
|
||||||
10. **staff_order_placed** (line 535-538):
|
|
||||||
```php
|
|
||||||
// OLD:
|
|
||||||
---
|
|
||||||
|
|
||||||
WooNooW Order Management
|
|
||||||
© {current_year} {site_name}';
|
|
||||||
|
|
||||||
// NEW:
|
|
||||||
';
|
|
||||||
// (Remove - staff doesn't need this footer)
|
|
||||||
```
|
|
||||||
|
|
||||||
11. **staff_order_confirmed** (line 582-585):
|
|
||||||
```php
|
|
||||||
// OLD:
|
|
||||||
---
|
|
||||||
|
|
||||||
WooNooW Order Management
|
|
||||||
© {current_year} {site_name}';
|
|
||||||
|
|
||||||
// NEW:
|
|
||||||
';
|
|
||||||
```
|
|
||||||
|
|
||||||
12. **staff_order_shipped** (line 618-621):
|
|
||||||
```php
|
|
||||||
// OLD:
|
|
||||||
---
|
|
||||||
|
|
||||||
WooNooW Order Management
|
|
||||||
© {current_year} {site_name}';
|
|
||||||
|
|
||||||
// NEW:
|
|
||||||
';
|
|
||||||
```
|
|
||||||
|
|
||||||
13. **staff_order_completed** (line 664-667):
|
|
||||||
```php
|
|
||||||
// OLD:
|
|
||||||
---
|
|
||||||
|
|
||||||
WooNooW Order Management
|
|
||||||
© {current_year} {site_name}';
|
|
||||||
|
|
||||||
// NEW:
|
|
||||||
';
|
|
||||||
```
|
|
||||||
|
|
||||||
14. **staff_order_cancelled** (line 716-719):
|
|
||||||
```php
|
|
||||||
// OLD:
|
|
||||||
---
|
|
||||||
|
|
||||||
WooNooW Order Management
|
|
||||||
© {current_year} {site_name}';
|
|
||||||
|
|
||||||
// NEW:
|
|
||||||
';
|
|
||||||
```
|
|
||||||
|
|
||||||
15. **staff_payment_received** (line 763-766):
|
|
||||||
```php
|
|
||||||
// OLD:
|
|
||||||
---
|
|
||||||
|
|
||||||
WooNooW Payment Management
|
|
||||||
© {current_year} {site_name}';
|
|
||||||
|
|
||||||
// NEW:
|
|
||||||
';
|
|
||||||
```
|
|
||||||
|
|
||||||
16. **staff_payment_failed** (line 809-812):
|
|
||||||
```php
|
|
||||||
// OLD:
|
|
||||||
---
|
|
||||||
|
|
||||||
WooNooW Payment Management
|
|
||||||
© {current_year} {site_name}';
|
|
||||||
|
|
||||||
// NEW:
|
|
||||||
';
|
|
||||||
```
|
|
||||||
|
|
||||||
## Summary:
|
|
||||||
|
|
||||||
- **Customer templates**: Wrap support text in `[card type="basic"]`, remove copyright
|
|
||||||
- **Staff templates**: Remove footer entirely (they don't need support contact)
|
|
||||||
- **All templates**: Remove `© {current_year} {site_name}` (handled by global footer)
|
|
||||||
Reference in New Issue
Block a user