Files
WooNooW/includes/Email/TEMPLATE_USAGE_GUIDE.md
dwindown 4471cd600f 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: ![alt](url)

 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
2025-11-15 20:05:50 +07:00

12 KiB

Email Template Usage Guide

How to Use Default Templates

Quick Start

The DefaultTemplates class provides production-ready email templates for all notification types.

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:

$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

'{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

'{customer_name}'       // Customer's full name
'{customer_email}'      // Customer's email address
'{customer_phone}'      // Customer's phone number

Payment Variables

'{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

'{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

'{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

'{site_name}'           // Store name
'{store_url}'           // Store homepage URL
'{support_email}'       // Support email address
'{current_year}'        // Current year (for copyright)

VIP Variables

'{vip_free_shipping_threshold}' // Free shipping threshold for VIP

Example: Sending Order Placed Email

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:

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!