feat: Complete markdown syntax refinement and variable protection
✅ New cleaner syntax implemented: - [card:type] instead of [card type='type'] - [button:style](url)Text[/button] instead of [button url='...' style='...'] - Standard markdown images:  ✅ Variable protection from markdown parsing: - Variables with underscores (e.g., {order_items_table}) now protected - HTML comment placeholders prevent italic/bold parsing - All variables render correctly in preview ✅ Button rendering fixes: - Buttons work in Visual mode inside cards - Buttons work in Preview mode - Button clicks prevented in visual editor - Proper styling for solid and outline buttons ✅ Backward compatibility: - Old syntax still supported - No breaking changes ✅ Bug fixes: - Fixed order_item_table → order_items_table naming - Fixed button regex to match across newlines - Added button/image parsing to parseMarkdownBasics - Prevented button clicks on .button and .button-outline classes 📚 Documentation: - NEW_MARKDOWN_SYNTAX.md - Complete user guide - MARKDOWN_SYNTAX_AND_VARIABLES.md - Technical analysis
This commit is contained in:
338
includes/Email/TEMPLATE_USAGE_GUIDE.md
Normal file
338
includes/Email/TEMPLATE_USAGE_GUIDE.md
Normal file
@@ -0,0 +1,338 @@
|
||||
# Email Template Usage Guide
|
||||
|
||||
## How to Use Default Templates
|
||||
|
||||
### Quick Start
|
||||
|
||||
The `DefaultTemplates` class provides production-ready email templates for all notification types.
|
||||
|
||||
```php
|
||||
use WooNooW\Email\DefaultTemplates;
|
||||
|
||||
// Get all templates
|
||||
$templates = DefaultTemplates::get_all_templates();
|
||||
|
||||
// Get specific template
|
||||
$customerOrderPlaced = $templates['customer']['order_placed'];
|
||||
$staffOrderPlaced = $templates['staff']['order_placed'];
|
||||
|
||||
// Get default subject
|
||||
$subject = DefaultTemplates::get_default_subject('customer', 'order_placed');
|
||||
// Returns: "Your order #{order_number} has been received"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Template Structure
|
||||
|
||||
### Available Recipients
|
||||
- `customer` - Emails sent to customers
|
||||
- `staff` - Emails sent to store staff/admin
|
||||
|
||||
### Available Events
|
||||
|
||||
**Customer Events:**
|
||||
- `order_placed` - When customer places an order
|
||||
- `order_confirmed` - When order is confirmed by staff
|
||||
- `order_shipped` - When order is shipped
|
||||
- `order_completed` - When order is delivered
|
||||
- `order_cancelled` - When order is cancelled
|
||||
- `payment_received` - When payment is successful
|
||||
- `payment_failed` - When payment fails
|
||||
- `customer_registered` - When customer creates account
|
||||
- `customer_vip_upgraded` - When customer becomes VIP
|
||||
|
||||
**Staff Events:**
|
||||
- `order_placed` - New order notification
|
||||
- `order_confirmed` - Order confirmed notification
|
||||
- `order_shipped` - Order shipped notification
|
||||
- `order_completed` - Order completed notification
|
||||
- `order_cancelled` - Order cancelled notification
|
||||
- `payment_received` - Payment received notification
|
||||
- `payment_failed` - Payment failed notification
|
||||
|
||||
---
|
||||
|
||||
## Variable Replacement
|
||||
|
||||
Templates use `{variable_name}` syntax. Replace these with actual data before sending:
|
||||
|
||||
```php
|
||||
$template = $templates['customer']['order_placed'];
|
||||
$subject = DefaultTemplates::get_default_subject('customer', 'order_placed');
|
||||
|
||||
// Replace variables
|
||||
$variables = [
|
||||
'customer_name' => $order->get_billing_first_name(),
|
||||
'order_number' => $order->get_order_number(),
|
||||
'order_date' => $order->get_date_created()->format('F j, Y'),
|
||||
'order_total' => $order->get_formatted_order_total(),
|
||||
'order_url' => $order->get_view_order_url(),
|
||||
'payment_method' => $order->get_payment_method_title(),
|
||||
'order_item_table' => $this->generate_order_items_table($order),
|
||||
'support_email' => get_option('admin_email'),
|
||||
'current_year' => date('Y'),
|
||||
'site_name' => get_bloginfo('name'),
|
||||
];
|
||||
|
||||
foreach ($variables as $key => $value) {
|
||||
$template = str_replace('{' . $key . '}', $value, $template);
|
||||
$subject = str_replace('{' . $key . '}', $value, $subject);
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Complete Variable Reference
|
||||
|
||||
### Order Variables
|
||||
```php
|
||||
'{order_number}' // Order ID/number
|
||||
'{order_date}' // Order creation date
|
||||
'{order_total}' // Total amount with currency
|
||||
'{order_url}' // Link to view order
|
||||
'{order_item_table}' // HTML table of order items
|
||||
'{completion_date}' // Order completion date
|
||||
```
|
||||
|
||||
### Customer Variables
|
||||
```php
|
||||
'{customer_name}' // Customer's full name
|
||||
'{customer_email}' // Customer's email address
|
||||
'{customer_phone}' // Customer's phone number
|
||||
```
|
||||
|
||||
### Payment Variables
|
||||
```php
|
||||
'{payment_method}' // Payment method name
|
||||
'{payment_status}' // Payment status
|
||||
'{payment_date}' // Payment date
|
||||
'{transaction_id}' // Payment transaction ID
|
||||
'{payment_retry_url}' // URL to retry failed payment
|
||||
```
|
||||
|
||||
### Shipping Variables
|
||||
```php
|
||||
'{tracking_number}' // Shipment tracking number
|
||||
'{tracking_url}' // Tracking URL
|
||||
'{shipping_carrier}' // Carrier name (e.g., "FedEx")
|
||||
'{shipping_address}' // Full shipping address
|
||||
'{billing_address}' // Full billing address
|
||||
```
|
||||
|
||||
### URL Variables
|
||||
```php
|
||||
'{order_url}' // Order details page
|
||||
'{review_url}' // Leave review page
|
||||
'{shop_url}' // Shop homepage
|
||||
'{my_account_url}' // Customer account page
|
||||
'{vip_dashboard_url}' // VIP member dashboard
|
||||
```
|
||||
|
||||
### Store Variables
|
||||
```php
|
||||
'{site_name}' // Store name
|
||||
'{store_url}' // Store homepage URL
|
||||
'{support_email}' // Support email address
|
||||
'{current_year}' // Current year (for copyright)
|
||||
```
|
||||
|
||||
### VIP Variables
|
||||
```php
|
||||
'{vip_free_shipping_threshold}' // Free shipping threshold for VIP
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Example: Sending Order Placed Email
|
||||
|
||||
```php
|
||||
use WooNooW\Email\DefaultTemplates;
|
||||
|
||||
class OrderNotification {
|
||||
|
||||
public function send_order_placed_email($order_id) {
|
||||
$order = wc_get_order($order_id);
|
||||
|
||||
// Get template and subject
|
||||
$templates = DefaultTemplates::get_all_templates();
|
||||
$body = $templates['customer']['order_placed'];
|
||||
$subject = DefaultTemplates::get_default_subject('customer', 'order_placed');
|
||||
|
||||
// Prepare variables
|
||||
$variables = [
|
||||
'customer_name' => $order->get_billing_first_name() . ' ' . $order->get_billing_last_name(),
|
||||
'order_number' => $order->get_order_number(),
|
||||
'order_date' => $order->get_date_created()->format('F j, Y g:i A'),
|
||||
'order_total' => $order->get_formatted_order_total(),
|
||||
'order_url' => $order->get_view_order_url(),
|
||||
'payment_method' => $order->get_payment_method_title(),
|
||||
'order_item_table' => $this->generate_order_items_table($order),
|
||||
'support_email' => get_option('woocommerce_email_from_address'),
|
||||
'current_year' => date('Y'),
|
||||
'site_name' => get_bloginfo('name'),
|
||||
];
|
||||
|
||||
// Replace variables in body and subject
|
||||
foreach ($variables as $key => $value) {
|
||||
$body = str_replace('{' . $key . '}', $value, $body);
|
||||
$subject = str_replace('{' . $key . '}', $value, $subject);
|
||||
}
|
||||
|
||||
// Convert markdown/card syntax to HTML
|
||||
$html = $this->parse_email_template($body);
|
||||
|
||||
// Send email
|
||||
$headers = ['Content-Type: text/html; charset=UTF-8'];
|
||||
wp_mail(
|
||||
$order->get_billing_email(),
|
||||
$subject,
|
||||
$html,
|
||||
$headers
|
||||
);
|
||||
}
|
||||
|
||||
private function generate_order_items_table($order) {
|
||||
$html = '<table style="width: 100%; border-collapse: collapse; margin: 16px 0;">';
|
||||
$html .= '<thead><tr style="background: #f5f5f5;">';
|
||||
$html .= '<th style="padding: 12px; text-align: left; border-bottom: 2px solid #ddd;">Product</th>';
|
||||
$html .= '<th style="padding: 12px; text-align: center; border-bottom: 2px solid #ddd;">Qty</th>';
|
||||
$html .= '<th style="padding: 12px; text-align: right; border-bottom: 2px solid #ddd;">Price</th>';
|
||||
$html .= '</tr></thead><tbody>';
|
||||
|
||||
foreach ($order->get_items() as $item) {
|
||||
$product = $item->get_product();
|
||||
$html .= '<tr>';
|
||||
$html .= '<td style="padding: 12px; border-bottom: 1px solid #eee;">';
|
||||
$html .= '<strong>' . $item->get_name() . '</strong>';
|
||||
$html .= '</td>';
|
||||
$html .= '<td style="padding: 12px; text-align: center; border-bottom: 1px solid #eee;">' . $item->get_quantity() . '</td>';
|
||||
$html .= '<td style="padding: 12px; text-align: right; border-bottom: 1px solid #eee;">' . wc_price($item->get_total()) . '</td>';
|
||||
$html .= '</tr>';
|
||||
}
|
||||
|
||||
$html .= '</tbody></table>';
|
||||
return $html;
|
||||
}
|
||||
|
||||
private function parse_email_template($content) {
|
||||
// Parse [card] blocks
|
||||
$content = preg_replace_callback(
|
||||
'/\[card(?:\s+type="([^"]+)")?\](.*?)\[\/card\]/s',
|
||||
function($matches) {
|
||||
$type = $matches[1] ?? 'default';
|
||||
$cardContent = $matches[2];
|
||||
$class = 'card' . ($type !== 'default' ? ' card-' . $type : '');
|
||||
return '<div class="' . $class . '">' . $cardContent . '</div>';
|
||||
},
|
||||
$content
|
||||
);
|
||||
|
||||
// Parse [button] shortcodes
|
||||
$content = preg_replace(
|
||||
'/\[button\s+url="([^"]+)"(?:\s+style="([^"]+)")?\]([^\[]+)\[\/button\]/',
|
||||
'<p style="text-align: center;"><a href="$1" class="button">$3</a></p>',
|
||||
$content
|
||||
);
|
||||
|
||||
// Parse markdown basics
|
||||
$content = preg_replace('/\*\*([^*]+)\*\*/', '<strong>$1</strong>', $content);
|
||||
$content = preg_replace('/^---$/m', '<hr>', $content);
|
||||
|
||||
// Wrap in email template
|
||||
return $this->wrap_in_email_template($content);
|
||||
}
|
||||
|
||||
private function wrap_in_email_template($content) {
|
||||
// Get email settings from database
|
||||
$settings = get_option('woonoow_email_settings', []);
|
||||
$primaryColor = $settings['primary_color'] ?? '#7f54b3';
|
||||
$heroGradientStart = $settings['hero_gradient_start'] ?? '#667eea';
|
||||
$heroGradientEnd = $settings['hero_gradient_end'] ?? '#764ba2';
|
||||
|
||||
return '
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
body { font-family: Arial, sans-serif; background: #f8f8f8; margin: 0; padding: 20px; }
|
||||
.container { max-width: 600px; margin: 0 auto; }
|
||||
.card { background: #ffffff; border-radius: 8px; margin-bottom: 24px; padding: 32px 40px; }
|
||||
.card-hero { background: linear-gradient(135deg, ' . $heroGradientStart . ' 0%, ' . $heroGradientEnd . ' 100%); color: #ffffff; }
|
||||
.card-success { background: linear-gradient(135deg, ' . $heroGradientStart . ' 0%, ' . $heroGradientEnd . ' 100%); color: #ffffff; }
|
||||
.card-info { background: #f0f7ff; border: 1px solid #0071e3; }
|
||||
.card-warning { background: #fff8e1; border: 1px solid #ff9800; }
|
||||
.button { display: inline-block; background: ' . $primaryColor . '; color: #ffffff; padding: 14px 28px; border-radius: 6px; text-decoration: none; font-weight: 600; }
|
||||
hr { border: none; border-top: 1px solid #ddd; margin: 20px 0; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
' . $content . '
|
||||
</div>
|
||||
</body>
|
||||
</html>';
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Integration with WooCommerce
|
||||
|
||||
Hook into WooCommerce order status changes:
|
||||
|
||||
```php
|
||||
add_action('woocommerce_order_status_processing', 'send_order_placed_email', 10, 1);
|
||||
add_action('woocommerce_order_status_completed', 'send_order_completed_email', 10, 1);
|
||||
add_action('woocommerce_order_status_cancelled', 'send_order_cancelled_email', 10, 1);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Customization
|
||||
|
||||
Store owners can customize templates in the admin panel:
|
||||
1. Navigate to Settings > Notifications
|
||||
2. Select recipient (Customer/Staff) and event
|
||||
3. Edit template using:
|
||||
- **Visual Builder** - Drag-and-drop blocks
|
||||
- **Code Mode** - Edit markdown/HTML directly
|
||||
- **Preview** - See live preview with branding
|
||||
|
||||
Templates support:
|
||||
- Custom branding colors
|
||||
- Logo upload
|
||||
- Social media links
|
||||
- Custom footer text
|
||||
- Variable insertion
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Always replace variables** before sending emails
|
||||
2. **Test emails** with sample data first
|
||||
3. **Use appropriate card types**:
|
||||
- `hero` - Welcome messages, big announcements
|
||||
- `success` - Positive confirmations
|
||||
- `info` - Informational messages
|
||||
- `warning` - Alerts, issues
|
||||
- `default` - General content
|
||||
|
||||
4. **Keep templates clean** - Don't over-customize
|
||||
5. **Use variables** instead of hardcoding data
|
||||
6. **Test on mobile** - Emails are responsive
|
||||
|
||||
---
|
||||
|
||||
## Support
|
||||
|
||||
For questions or issues:
|
||||
- Check `EMAIL_BUILDER_COMPLETE.md` for system overview
|
||||
- Review template syntax in `DefaultTemplates.php`
|
||||
- Test in admin panel Preview tab before sending
|
||||
|
||||
---
|
||||
|
||||
**Templates are production-ready and require no modification to work!**
|
||||
Reference in New Issue
Block a user