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:
@@ -58,6 +58,7 @@ class Assets {
|
||||
'standaloneMode' => false,
|
||||
'wpAdminUrl' => admin_url('admin.php?page=woonoow'),
|
||||
'isAuthenticated' => is_user_logged_in(),
|
||||
'pluginUrl' => trailingslashit(plugins_url('/', dirname(__DIR__))),
|
||||
]);
|
||||
wp_add_inline_script($handle, 'window.WNW_CONFIG = window.WNW_CONFIG || WNW_CONFIG;', 'after');
|
||||
|
||||
@@ -162,6 +163,7 @@ class Assets {
|
||||
'standaloneMode' => false,
|
||||
'wpAdminUrl' => admin_url('admin.php?page=woonoow'),
|
||||
'isAuthenticated' => is_user_logged_in(),
|
||||
'pluginUrl' => trailingslashit(plugins_url('/', dirname(__DIR__))),
|
||||
]);
|
||||
|
||||
// WordPress REST API settings (for media upload compatibility)
|
||||
|
||||
@@ -9,10 +9,12 @@
|
||||
|
||||
namespace WooNooW\Api;
|
||||
|
||||
use WP_REST_Controller;
|
||||
use WP_REST_Server;
|
||||
use WP_REST_Request;
|
||||
use WP_REST_Response;
|
||||
use WP_Error;
|
||||
use WooNooW\Core\Notifications\TemplateProvider;
|
||||
use WooNooW\Core\Notifications\EventRegistry;
|
||||
use WooNooW\Core\Notifications\PushNotificationHandler;
|
||||
|
||||
class NotificationsController {
|
||||
@@ -67,13 +69,18 @@ class NotificationsController {
|
||||
],
|
||||
]);
|
||||
|
||||
// GET /woonoow/v1/notifications/templates/:eventId/:channelId
|
||||
// GET/PUT /woonoow/v1/notifications/templates/:eventId/:channelId
|
||||
register_rest_route($this->namespace, '/' . $this->rest_base . '/templates/(?P<eventId>[a-zA-Z0-9_-]+)/(?P<channelId>[a-zA-Z0-9_-]+)', [
|
||||
[
|
||||
'methods' => 'GET',
|
||||
'callback' => [$this, 'get_template'],
|
||||
'permission_callback' => [$this, 'check_permission'],
|
||||
],
|
||||
[
|
||||
'methods' => 'PUT',
|
||||
'callback' => [$this, 'save_template'],
|
||||
'permission_callback' => [$this, 'check_permission'],
|
||||
],
|
||||
]);
|
||||
|
||||
// POST /woonoow/v1/notifications/templates
|
||||
@@ -235,104 +242,31 @@ class NotificationsController {
|
||||
* @return WP_REST_Response
|
||||
*/
|
||||
public function get_events(WP_REST_Request $request) {
|
||||
// Get saved settings
|
||||
$settings = get_option('woonoow_notification_settings', []);
|
||||
|
||||
// Define default events (maps to WooCommerce emails)
|
||||
$events = [
|
||||
'orders' => [
|
||||
[
|
||||
'id' => 'order_placed',
|
||||
'label' => __('Order Placed', 'woonoow'),
|
||||
'description' => __('When a new order is placed', 'woonoow'),
|
||||
'category' => 'orders',
|
||||
'wc_email' => 'new_order',
|
||||
'enabled' => true,
|
||||
'channels' => $settings['order_placed']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'admin'], 'push' => ['enabled' => false, 'recipient' => 'admin']],
|
||||
],
|
||||
[
|
||||
'id' => 'order_processing',
|
||||
'label' => __('Order Processing', 'woonoow'),
|
||||
'description' => __('When order status changes to processing', 'woonoow'),
|
||||
'category' => 'orders',
|
||||
'wc_email' => 'customer_processing_order',
|
||||
'enabled' => true,
|
||||
'channels' => $settings['order_processing']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'customer'], 'push' => ['enabled' => false, 'recipient' => 'customer']],
|
||||
],
|
||||
[
|
||||
'id' => 'order_completed',
|
||||
'label' => __('Order Completed', 'woonoow'),
|
||||
'description' => __('When order is marked as completed', 'woonoow'),
|
||||
'category' => 'orders',
|
||||
'wc_email' => 'customer_completed_order',
|
||||
'enabled' => true,
|
||||
'channels' => $settings['order_completed']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'customer'], 'push' => ['enabled' => false, 'recipient' => 'customer']],
|
||||
],
|
||||
[
|
||||
'id' => 'order_cancelled',
|
||||
'label' => __('Order Cancelled', 'woonoow'),
|
||||
'description' => __('When order is cancelled', 'woonoow'),
|
||||
'category' => 'orders',
|
||||
'wc_email' => 'cancelled_order',
|
||||
'enabled' => true,
|
||||
'channels' => $settings['order_cancelled']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'admin'], 'push' => ['enabled' => false, 'recipient' => 'admin']],
|
||||
],
|
||||
[
|
||||
'id' => 'order_refunded',
|
||||
'label' => __('Order Refunded', 'woonoow'),
|
||||
'description' => __('When order is refunded', 'woonoow'),
|
||||
'category' => 'orders',
|
||||
'wc_email' => 'customer_refunded_order',
|
||||
'enabled' => true,
|
||||
'channels' => $settings['order_refunded']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'customer'], 'push' => ['enabled' => false, 'recipient' => 'customer']],
|
||||
],
|
||||
],
|
||||
'products' => [
|
||||
[
|
||||
'id' => 'low_stock',
|
||||
'label' => __('Low Stock Alert', 'woonoow'),
|
||||
'description' => __('When product stock is low', 'woonoow'),
|
||||
'category' => 'products',
|
||||
'wc_email' => 'low_stock',
|
||||
'enabled' => true,
|
||||
'channels' => $settings['low_stock']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'admin'], 'push' => ['enabled' => false, 'recipient' => 'admin']],
|
||||
],
|
||||
[
|
||||
'id' => 'out_of_stock',
|
||||
'label' => __('Out of Stock Alert', 'woonoow'),
|
||||
'description' => __('When product is out of stock', 'woonoow'),
|
||||
'category' => 'products',
|
||||
'wc_email' => 'no_stock',
|
||||
'enabled' => true,
|
||||
'channels' => $settings['out_of_stock']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'admin'], 'push' => ['enabled' => false, 'recipient' => 'admin']],
|
||||
],
|
||||
],
|
||||
'customers' => [
|
||||
[
|
||||
'id' => 'new_customer',
|
||||
'label' => __('New Customer', 'woonoow'),
|
||||
'description' => __('When a new customer registers', 'woonoow'),
|
||||
'category' => 'customers',
|
||||
'wc_email' => 'customer_new_account',
|
||||
'enabled' => true,
|
||||
'channels' => $settings['new_customer']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'customer'], 'push' => ['enabled' => false, 'recipient' => 'customer']],
|
||||
],
|
||||
[
|
||||
'id' => 'customer_note',
|
||||
'label' => __('Customer Note Added', 'woonoow'),
|
||||
'description' => __('When a note is added to customer order', 'woonoow'),
|
||||
'category' => 'customers',
|
||||
'wc_email' => 'customer_note',
|
||||
'enabled' => true,
|
||||
'channels' => $settings['customer_note']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'customer'], 'push' => ['enabled' => false, 'recipient' => 'customer']],
|
||||
],
|
||||
],
|
||||
];
|
||||
// Get all events from EventRegistry (single source of truth)
|
||||
$all_events = EventRegistry::get_all_events();
|
||||
|
||||
// Allow addons to add custom events
|
||||
$events = apply_filters('woonoow_notification_events', $events);
|
||||
// Group by category and add settings
|
||||
$grouped_events = [];
|
||||
foreach ($all_events as $event) {
|
||||
$category = $event['category'];
|
||||
if (!isset($grouped_events[$category])) {
|
||||
$grouped_events[$category] = [];
|
||||
}
|
||||
|
||||
// Add channels from settings
|
||||
$event_id = $event['id'];
|
||||
$event['channels'] = $settings[$event_id]['channels'] ?? [
|
||||
'email' => ['enabled' => false, 'recipient' => $event['recipient_type']],
|
||||
'push' => ['enabled' => false, 'recipient' => $event['recipient_type']]
|
||||
];
|
||||
$event['recipients'] = [$event['recipient_type']];
|
||||
|
||||
$grouped_events[$category][] = $event;
|
||||
}
|
||||
|
||||
return new WP_REST_Response($events, 200);
|
||||
return new WP_REST_Response($grouped_events, 200);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -389,111 +323,31 @@ class NotificationsController {
|
||||
* @return array
|
||||
*/
|
||||
private function get_all_events() {
|
||||
// Get saved settings
|
||||
// Use EventRegistry - same as get_events() but returns ungrouped
|
||||
$settings = get_option('woonoow_notification_settings', []);
|
||||
|
||||
// Define all events
|
||||
$events = [
|
||||
'orders' => [
|
||||
[
|
||||
'id' => 'order_placed',
|
||||
'label' => __('Order Placed', 'woonoow'),
|
||||
'description' => __('When a new order is placed', 'woonoow'),
|
||||
'category' => 'orders',
|
||||
'wc_email' => 'new_order',
|
||||
'enabled' => true,
|
||||
'recipient_type' => 'staff',
|
||||
'channels' => $settings['order_placed']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'admin'], 'push' => ['enabled' => false, 'recipient' => 'admin']],
|
||||
],
|
||||
[
|
||||
'id' => 'order_processing',
|
||||
'label' => __('Order Processing', 'woonoow'),
|
||||
'description' => __('When order status changes to processing', 'woonoow'),
|
||||
'category' => 'orders',
|
||||
'wc_email' => 'customer_processing_order',
|
||||
'enabled' => true,
|
||||
'recipient_type' => 'customer',
|
||||
'channels' => $settings['order_processing']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'customer'], 'push' => ['enabled' => false, 'recipient' => 'customer']],
|
||||
],
|
||||
[
|
||||
'id' => 'order_completed',
|
||||
'label' => __('Order Completed', 'woonoow'),
|
||||
'description' => __('When order is marked as completed', 'woonoow'),
|
||||
'category' => 'orders',
|
||||
'wc_email' => 'customer_completed_order',
|
||||
'enabled' => true,
|
||||
'recipient_type' => 'customer',
|
||||
'channels' => $settings['order_completed']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'customer'], 'push' => ['enabled' => false, 'recipient' => 'customer']],
|
||||
],
|
||||
[
|
||||
'id' => 'order_cancelled',
|
||||
'label' => __('Order Cancelled', 'woonoow'),
|
||||
'description' => __('When order is cancelled', 'woonoow'),
|
||||
'category' => 'orders',
|
||||
'wc_email' => 'cancelled_order',
|
||||
'enabled' => true,
|
||||
'recipient_type' => 'staff',
|
||||
'channels' => $settings['order_cancelled']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'admin'], 'push' => ['enabled' => false, 'recipient' => 'admin']],
|
||||
],
|
||||
[
|
||||
'id' => 'order_refunded',
|
||||
'label' => __('Order Refunded', 'woonoow'),
|
||||
'description' => __('When order is refunded', 'woonoow'),
|
||||
'category' => 'orders',
|
||||
'wc_email' => 'customer_refunded_order',
|
||||
'enabled' => true,
|
||||
'recipient_type' => 'customer',
|
||||
'channels' => $settings['order_refunded']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'customer'], 'push' => ['enabled' => false, 'recipient' => 'customer']],
|
||||
],
|
||||
],
|
||||
'products' => [
|
||||
[
|
||||
'id' => 'low_stock',
|
||||
'label' => __('Low Stock Alert', 'woonoow'),
|
||||
'description' => __('When product stock is low', 'woonoow'),
|
||||
'category' => 'products',
|
||||
'wc_email' => 'low_stock',
|
||||
'enabled' => true,
|
||||
'recipient_type' => 'staff',
|
||||
'channels' => $settings['low_stock']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'admin'], 'push' => ['enabled' => false, 'recipient' => 'admin']],
|
||||
],
|
||||
[
|
||||
'id' => 'out_of_stock',
|
||||
'label' => __('Out of Stock Alert', 'woonoow'),
|
||||
'description' => __('When product is out of stock', 'woonoow'),
|
||||
'category' => 'products',
|
||||
'wc_email' => 'no_stock',
|
||||
'enabled' => true,
|
||||
'recipient_type' => 'staff',
|
||||
'channels' => $settings['out_of_stock']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'admin'], 'push' => ['enabled' => false, 'recipient' => 'admin']],
|
||||
],
|
||||
],
|
||||
'customers' => [
|
||||
[
|
||||
'id' => 'new_customer',
|
||||
'label' => __('New Customer', 'woonoow'),
|
||||
'description' => __('When a new customer registers', 'woonoow'),
|
||||
'category' => 'customers',
|
||||
'wc_email' => 'customer_new_account',
|
||||
'enabled' => true,
|
||||
'recipient_type' => 'customer',
|
||||
'channels' => $settings['new_customer']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'customer'], 'push' => ['enabled' => false, 'recipient' => 'customer']],
|
||||
],
|
||||
[
|
||||
'id' => 'customer_note',
|
||||
'label' => __('Customer Note Added', 'woonoow'),
|
||||
'description' => __('When a note is added to customer order', 'woonoow'),
|
||||
'category' => 'customers',
|
||||
'wc_email' => 'customer_note',
|
||||
'enabled' => true,
|
||||
'recipient_type' => 'customer',
|
||||
'channels' => $settings['customer_note']['channels'] ?? ['email' => ['enabled' => false, 'recipient' => 'customer'], 'push' => ['enabled' => false, 'recipient' => 'customer']],
|
||||
],
|
||||
],
|
||||
];
|
||||
// Get all events from EventRegistry (single source of truth)
|
||||
$all_events = EventRegistry::get_all_events();
|
||||
|
||||
// Allow addons to add custom events
|
||||
return apply_filters('woonoow_notification_events', $events);
|
||||
// Group by category and add settings
|
||||
$grouped_events = [];
|
||||
foreach ($all_events as $event) {
|
||||
$category = $event['category'];
|
||||
if (!isset($grouped_events[$category])) {
|
||||
$grouped_events[$category] = [];
|
||||
}
|
||||
|
||||
// Add channels from settings
|
||||
$event_id = $event['id'];
|
||||
$event['channels'] = $settings[$event_id]['channels'] ?? [
|
||||
'email' => ['enabled' => false, 'recipient' => $event['recipient_type']],
|
||||
'push' => ['enabled' => false, 'recipient' => $event['recipient_type']]
|
||||
];
|
||||
|
||||
$grouped_events[$category][] = $event;
|
||||
}
|
||||
|
||||
return $grouped_events;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -575,8 +429,9 @@ class NotificationsController {
|
||||
public function get_template(WP_REST_Request $request) {
|
||||
$event_id = $request->get_param('eventId');
|
||||
$channel_id = $request->get_param('channelId');
|
||||
$recipient_type = $request->get_param('recipient') ?? 'customer';
|
||||
|
||||
$template = TemplateProvider::get_template($event_id, $channel_id);
|
||||
$template = TemplateProvider::get_template($event_id, $channel_id, $recipient_type);
|
||||
|
||||
if (!$template) {
|
||||
return new WP_Error(
|
||||
@@ -625,23 +480,20 @@ class NotificationsController {
|
||||
public function save_template(WP_REST_Request $request) {
|
||||
$event_id = $request->get_param('eventId');
|
||||
$channel_id = $request->get_param('channelId');
|
||||
$recipient_type = $request->get_param('recipient') ?? 'customer';
|
||||
$subject = $request->get_param('subject');
|
||||
$body = $request->get_param('body');
|
||||
$variables = $request->get_param('variables');
|
||||
|
||||
if (empty($event_id) || empty($channel_id)) {
|
||||
return new WP_Error(
|
||||
'invalid_params',
|
||||
__('Event ID and Channel ID are required', 'woonoow'),
|
||||
['status' => 400]
|
||||
);
|
||||
}
|
||||
|
||||
$success = TemplateProvider::save_template($event_id, $channel_id, [
|
||||
$template = [
|
||||
'subject' => $subject,
|
||||
'body' => $body,
|
||||
]);
|
||||
'variables' => $variables,
|
||||
];
|
||||
|
||||
if (!$success) {
|
||||
$result = TemplateProvider::save_template($event_id, $channel_id, $template, $recipient_type);
|
||||
|
||||
if (!$result) {
|
||||
return new WP_Error(
|
||||
'save_failed',
|
||||
__('Failed to save template', 'woonoow'),
|
||||
@@ -664,8 +516,9 @@ class NotificationsController {
|
||||
public function delete_template(WP_REST_Request $request) {
|
||||
$event_id = $request->get_param('eventId');
|
||||
$channel_id = $request->get_param('channelId');
|
||||
$recipient_type = $request->get_param('recipient') ?? 'customer';
|
||||
|
||||
TemplateProvider::delete_template($event_id, $channel_id);
|
||||
TemplateProvider::delete_template($event_id, $channel_id, $recipient_type);
|
||||
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
|
||||
@@ -1,14 +1,22 @@
|
||||
<?php
|
||||
/**
|
||||
* Default Email Templates
|
||||
* Default Email Templates (DEPRECATED)
|
||||
*
|
||||
* Provides default email content for all notification events
|
||||
* @deprecated Use WooNooW\Email\DefaultTemplates instead
|
||||
*
|
||||
* This file is kept for backwards compatibility only.
|
||||
* The new source of truth is /includes/Email/DefaultTemplates.php
|
||||
* which contains clean markdown templates without HTML tags.
|
||||
*
|
||||
* TemplateProvider now uses the new Email\DefaultTemplates directly.
|
||||
*
|
||||
* @package WooNooW
|
||||
*/
|
||||
|
||||
namespace WooNooW\Core\Notifications;
|
||||
|
||||
use WooNooW\Email\DefaultTemplates as NewDefaultTemplates;
|
||||
|
||||
class DefaultEmailTemplates {
|
||||
|
||||
/**
|
||||
@@ -19,25 +27,29 @@ class DefaultEmailTemplates {
|
||||
* @return array ['subject' => string, 'body' => string]
|
||||
*/
|
||||
public static function get_template($event_id, $recipient_type) {
|
||||
$templates = self::get_all_templates();
|
||||
// Get templates directly from this class
|
||||
$allTemplates = self::get_all_templates();
|
||||
|
||||
if (isset($templates[$event_id][$recipient_type])) {
|
||||
return $templates[$event_id][$recipient_type];
|
||||
// Check if event exists for this recipient type
|
||||
if (isset($allTemplates[$event_id][$recipient_type])) {
|
||||
return $allTemplates[$event_id][$recipient_type];
|
||||
}
|
||||
|
||||
// Fallback
|
||||
return [
|
||||
'subject' => __('Notification from {store_name}', 'woonoow'),
|
||||
'body' => '[card type="default"]<p>' . __('You have a new notification.', 'woonoow') . '</p>[/card]',
|
||||
'body' => '[card]' . __('You have a new notification.', 'woonoow') . '[/card]',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all default templates
|
||||
* Get all default templates (legacy method - kept for backwards compatibility)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private static function get_all_templates() {
|
||||
// This method is now deprecated but kept for backwards compatibility
|
||||
// Use WooNooW\Email\DefaultTemplates instead
|
||||
return [
|
||||
// ORDER EVENTS
|
||||
'order_placed' => [
|
||||
@@ -68,7 +80,7 @@ class DefaultEmailTemplates {
|
||||
{order_items_list}
|
||||
[/card]
|
||||
|
||||
[button link="{order_url}" style="solid"]' . __('View Order Details', 'woonoow') . '[/button]',
|
||||
[button url="{order_url}" style="solid"]' . __('View Order Details', 'woonoow') . '[/button]',
|
||||
],
|
||||
],
|
||||
|
||||
@@ -97,7 +109,7 @@ class DefaultEmailTemplates {
|
||||
{order_items_list}
|
||||
[/card]
|
||||
|
||||
[button link="{order_url}" style="solid"]' . __('Track Your Order', 'woonoow') . '[/button]',
|
||||
[button url="{order_url}" style="solid"]' . __('Track Your Order', 'woonoow') . '[/button]',
|
||||
],
|
||||
],
|
||||
|
||||
@@ -122,8 +134,8 @@ class DefaultEmailTemplates {
|
||||
<p>' . __('If you have any questions or concerns about your order, please don\'t hesitate to contact us.', 'woonoow') . '</p>
|
||||
[/card]
|
||||
|
||||
[button link="{order_url}" style="solid"]' . __('View Order', 'woonoow') . '[/button]
|
||||
[button link="{store_url}" style="outline"]' . __('Continue Shopping', 'woonoow') . '[/button]',
|
||||
[button url="{order_url}" style="solid"]' . __('View Order', 'woonoow') . '[/button]
|
||||
[button url="{store_url}" style="outline"]' . __('Continue Shopping', 'woonoow') . '[/button]',
|
||||
],
|
||||
],
|
||||
|
||||
@@ -143,7 +155,7 @@ class DefaultEmailTemplates {
|
||||
<p><strong>' . __('Cancelled Date:', 'woonoow') . '</strong> {order_date}</p>
|
||||
[/card]
|
||||
|
||||
[button link="{order_url}" style="solid"]' . __('View Order Details', 'woonoow') . '[/button]',
|
||||
[button url="{order_url}" style="solid"]' . __('View Order Details', 'woonoow') . '[/button]',
|
||||
],
|
||||
],
|
||||
|
||||
@@ -168,7 +180,7 @@ class DefaultEmailTemplates {
|
||||
<p>' . __('If you have any questions, please contact us.', 'woonoow') . '</p>
|
||||
[/card]
|
||||
|
||||
[button link="{order_url}" style="solid"]' . __('View Order', 'woonoow') . '[/button]',
|
||||
[button url="{order_url}" style="solid"]' . __('View Order', 'woonoow') . '[/button]',
|
||||
],
|
||||
],
|
||||
|
||||
@@ -194,7 +206,7 @@ class DefaultEmailTemplates {
|
||||
<p>' . __('Please restock this product to avoid running out of inventory.', 'woonoow') . '</p>
|
||||
[/card]
|
||||
|
||||
[button link="{product_url}" style="solid"]' . __('View Product', 'woonoow') . '[/button]',
|
||||
[button url="{product_url}" style="solid"]' . __('View Product', 'woonoow') . '[/button]',
|
||||
],
|
||||
],
|
||||
|
||||
@@ -218,7 +230,7 @@ class DefaultEmailTemplates {
|
||||
<p>' . __('This product is no longer available for purchase. Please restock as soon as possible.', 'woonoow') . '</p>
|
||||
[/card]
|
||||
|
||||
[button link="{product_url}" style="solid"]' . __('Manage Product', 'woonoow') . '[/button]',
|
||||
[button url="{product_url}" style="solid"]' . __('Manage Product', 'woonoow') . '[/button]',
|
||||
],
|
||||
],
|
||||
|
||||
@@ -248,8 +260,8 @@ class DefaultEmailTemplates {
|
||||
</ul>
|
||||
[/card]
|
||||
|
||||
[button link="{account_url}" style="solid"]' . __('Go to My Account', 'woonoow') . '[/button]
|
||||
[button link="{store_url}" style="outline"]' . __('Start Shopping', 'woonoow') . '[/button]',
|
||||
[button url="{account_url}" style="solid"]' . __('Go to My Account', 'woonoow') . '[/button]
|
||||
[button url="{store_url}" style="outline"]' . __('Start Shopping', 'woonoow') . '[/button]',
|
||||
],
|
||||
],
|
||||
|
||||
@@ -272,9 +284,29 @@ class DefaultEmailTemplates {
|
||||
<p>{customer_note}</p>
|
||||
[/card]
|
||||
|
||||
[button link="{order_url}" style="solid"]' . __('View Order', 'woonoow') . '[/button]',
|
||||
[button url="{order_url}" style="solid"]' . __('View Order', 'woonoow') . '[/button]',
|
||||
],
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all new templates (direct access to new class)
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_new_templates() {
|
||||
return NewDefaultTemplates::get_all_templates();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default subject from new templates
|
||||
*
|
||||
* @param string $recipient_type 'staff' or 'customer'
|
||||
* @param string $event_id Event ID
|
||||
* @return string
|
||||
*/
|
||||
public static function get_default_subject($recipient_type, $event_id) {
|
||||
return NewDefaultTemplates::get_default_subject($recipient_type, $event_id);
|
||||
}
|
||||
}
|
||||
|
||||
243
includes/Core/Notifications/EventRegistry.php
Normal file
243
includes/Core/Notifications/EventRegistry.php
Normal file
@@ -0,0 +1,243 @@
|
||||
<?php
|
||||
/**
|
||||
* Event Registry - Single Source of Truth for Notification Events
|
||||
*
|
||||
* Defines all notification events in the system with their metadata.
|
||||
* Other components query this registry instead of hardcoding event lists.
|
||||
*
|
||||
* @package WooNooW\Core\Notifications
|
||||
*/
|
||||
|
||||
namespace WooNooW\Core\Notifications;
|
||||
|
||||
class EventRegistry {
|
||||
|
||||
/**
|
||||
* Get all registered notification events
|
||||
*
|
||||
* This is the SINGLE SOURCE OF TRUTH for all events in the system.
|
||||
* All other components (API, TemplateProvider, etc.) must use this.
|
||||
*
|
||||
* @return array Event definitions with structure:
|
||||
* [
|
||||
* 'event_id' => [
|
||||
* 'id' => 'event_id',
|
||||
* 'label' => 'Human readable label',
|
||||
* 'description' => 'What triggers this event',
|
||||
* 'category' => 'orders|products|customers',
|
||||
* 'recipient_type' => 'staff|customer',
|
||||
* 'wc_email' => 'woocommerce_email_id',
|
||||
* 'enabled' => true|false,
|
||||
* ]
|
||||
* ]
|
||||
*/
|
||||
public static function get_all_events() {
|
||||
$events = [
|
||||
// STAFF EVENTS
|
||||
'order_placed' => [
|
||||
'id' => 'order_placed',
|
||||
'label' => __('Order Placed', 'woonoow'),
|
||||
'description' => __('When a new order is placed', 'woonoow'),
|
||||
'category' => 'orders',
|
||||
'recipient_type' => 'staff',
|
||||
'wc_email' => 'new_order',
|
||||
'enabled' => true,
|
||||
],
|
||||
'order_processing' => [
|
||||
'id' => 'order_processing',
|
||||
'label' => __('Order Processing', 'woonoow'),
|
||||
'description' => __('When order is confirmed and being processed', 'woonoow'),
|
||||
'category' => 'orders',
|
||||
'recipient_type' => 'staff',
|
||||
'wc_email' => 'customer_processing_order',
|
||||
'enabled' => true,
|
||||
],
|
||||
'order_shipped' => [
|
||||
'id' => 'order_shipped',
|
||||
'label' => __('Order Shipped', 'woonoow'),
|
||||
'description' => __('When order is shipped', 'woonoow'),
|
||||
'category' => 'orders',
|
||||
'recipient_type' => 'staff',
|
||||
'wc_email' => '',
|
||||
'enabled' => true,
|
||||
],
|
||||
'order_completed' => [
|
||||
'id' => 'order_completed',
|
||||
'label' => __('Order Completed', 'woonoow'),
|
||||
'description' => __('When order is marked as completed', 'woonoow'),
|
||||
'category' => 'orders',
|
||||
'recipient_type' => 'staff',
|
||||
'wc_email' => 'customer_completed_order',
|
||||
'enabled' => true,
|
||||
],
|
||||
'order_cancelled' => [
|
||||
'id' => 'order_cancelled',
|
||||
'label' => __('Order Cancelled', 'woonoow'),
|
||||
'description' => __('When order is cancelled', 'woonoow'),
|
||||
'category' => 'orders',
|
||||
'recipient_type' => 'staff',
|
||||
'wc_email' => 'cancelled_order',
|
||||
'enabled' => true,
|
||||
],
|
||||
'payment_received' => [
|
||||
'id' => 'payment_received',
|
||||
'label' => __('Payment Received', 'woonoow'),
|
||||
'description' => __('When payment is successfully received', 'woonoow'),
|
||||
'category' => 'orders',
|
||||
'recipient_type' => 'staff',
|
||||
'wc_email' => '',
|
||||
'enabled' => true,
|
||||
],
|
||||
'payment_failed' => [
|
||||
'id' => 'payment_failed',
|
||||
'label' => __('Payment Failed', 'woonoow'),
|
||||
'description' => __('When payment processing fails', 'woonoow'),
|
||||
'category' => 'orders',
|
||||
'recipient_type' => 'staff',
|
||||
'wc_email' => '',
|
||||
'enabled' => true,
|
||||
],
|
||||
|
||||
// CUSTOMER EVENTS
|
||||
'order_placed_customer' => [
|
||||
'id' => 'order_placed',
|
||||
'label' => __('Order Placed', 'woonoow'),
|
||||
'description' => __('When customer places an order', 'woonoow'),
|
||||
'category' => 'orders',
|
||||
'recipient_type' => 'customer',
|
||||
'wc_email' => 'customer_on_hold_order',
|
||||
'enabled' => true,
|
||||
],
|
||||
'order_processing_customer' => [
|
||||
'id' => 'order_processing',
|
||||
'label' => __('Order Processing', 'woonoow'),
|
||||
'description' => __('When order status changes to processing', 'woonoow'),
|
||||
'category' => 'orders',
|
||||
'recipient_type' => 'customer',
|
||||
'wc_email' => 'customer_processing_order',
|
||||
'enabled' => true,
|
||||
],
|
||||
'order_shipped_customer' => [
|
||||
'id' => 'order_shipped',
|
||||
'label' => __('Order Shipped', 'woonoow'),
|
||||
'description' => __('When order is shipped with tracking', 'woonoow'),
|
||||
'category' => 'orders',
|
||||
'recipient_type' => 'customer',
|
||||
'wc_email' => '',
|
||||
'enabled' => true,
|
||||
],
|
||||
'order_completed_customer' => [
|
||||
'id' => 'order_completed',
|
||||
'label' => __('Order Completed', 'woonoow'),
|
||||
'description' => __('When order is delivered/completed', 'woonoow'),
|
||||
'category' => 'orders',
|
||||
'recipient_type' => 'customer',
|
||||
'wc_email' => 'customer_completed_order',
|
||||
'enabled' => true,
|
||||
],
|
||||
'order_cancelled_customer' => [
|
||||
'id' => 'order_cancelled',
|
||||
'label' => __('Order Cancelled', 'woonoow'),
|
||||
'description' => __('When order is cancelled', 'woonoow'),
|
||||
'category' => 'orders',
|
||||
'recipient_type' => 'customer',
|
||||
'wc_email' => 'customer_refunded_order',
|
||||
'enabled' => true,
|
||||
],
|
||||
'payment_received_customer' => [
|
||||
'id' => 'payment_received',
|
||||
'label' => __('Payment Received', 'woonoow'),
|
||||
'description' => __('When payment is confirmed', 'woonoow'),
|
||||
'category' => 'orders',
|
||||
'recipient_type' => 'customer',
|
||||
'wc_email' => '',
|
||||
'enabled' => true,
|
||||
],
|
||||
'payment_failed_customer' => [
|
||||
'id' => 'payment_failed',
|
||||
'label' => __('Payment Failed', 'woonoow'),
|
||||
'description' => __('When payment fails - prompt retry', 'woonoow'),
|
||||
'category' => 'orders',
|
||||
'recipient_type' => 'customer',
|
||||
'wc_email' => 'customer_failed_order',
|
||||
'enabled' => true,
|
||||
],
|
||||
'new_customer' => [
|
||||
'id' => 'new_customer',
|
||||
'label' => __('New Customer', 'woonoow'),
|
||||
'description' => __('When a new customer registers', 'woonoow'),
|
||||
'category' => 'customers',
|
||||
'recipient_type' => 'customer',
|
||||
'wc_email' => 'customer_new_account',
|
||||
'enabled' => true,
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Filter: woonoow_notification_events_registry
|
||||
*
|
||||
* Allows plugins/themes to add custom notification events
|
||||
*
|
||||
* @param array $events Event definitions
|
||||
*/
|
||||
return apply_filters('woonoow_notification_events_registry', $events);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get events by recipient type
|
||||
*
|
||||
* @param string $recipient_type 'staff' or 'customer'
|
||||
* @return array Filtered events
|
||||
*/
|
||||
public static function get_events_by_recipient($recipient_type) {
|
||||
$all_events = self::get_all_events();
|
||||
|
||||
return array_filter($all_events, function($event) use ($recipient_type) {
|
||||
return $event['recipient_type'] === $recipient_type;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get events by category
|
||||
*
|
||||
* @param string $category 'orders', 'products', 'customers'
|
||||
* @return array Filtered events
|
||||
*/
|
||||
public static function get_events_by_category($category) {
|
||||
$all_events = self::get_all_events();
|
||||
|
||||
return array_filter($all_events, function($event) use ($category) {
|
||||
return $event['category'] === $category;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get single event definition
|
||||
*
|
||||
* @param string $event_id Event ID
|
||||
* @param string $recipient_type Recipient type
|
||||
* @return array|null Event definition or null if not found
|
||||
*/
|
||||
public static function get_event($event_id, $recipient_type) {
|
||||
$all_events = self::get_all_events();
|
||||
|
||||
foreach ($all_events as $event) {
|
||||
if ($event['id'] === $event_id && $event['recipient_type'] === $recipient_type) {
|
||||
return $event;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if event exists
|
||||
*
|
||||
* @param string $event_id Event ID
|
||||
* @param string $recipient_type Recipient type
|
||||
* @return bool
|
||||
*/
|
||||
public static function event_exists($event_id, $recipient_type) {
|
||||
return self::get_event($event_id, $recipient_type) !== null;
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
namespace WooNooW\Core\Notifications;
|
||||
|
||||
use WooNooW\Email\DefaultTemplates as EmailDefaultTemplates;
|
||||
|
||||
class TemplateProvider {
|
||||
|
||||
/**
|
||||
@@ -35,12 +37,13 @@ class TemplateProvider {
|
||||
*
|
||||
* @param string $event_id Event ID
|
||||
* @param string $channel_id Channel ID
|
||||
* @param string $recipient_type Recipient type ('customer' or 'staff')
|
||||
* @return array|null
|
||||
*/
|
||||
public static function get_template($event_id, $channel_id) {
|
||||
public static function get_template($event_id, $channel_id, $recipient_type = 'customer') {
|
||||
$templates = self::get_templates();
|
||||
|
||||
$key = "{$event_id}_{$channel_id}";
|
||||
$key = "{$recipient_type}_{$event_id}_{$channel_id}";
|
||||
|
||||
if (isset($templates[$key])) {
|
||||
return $templates[$key];
|
||||
@@ -48,7 +51,12 @@ class TemplateProvider {
|
||||
|
||||
// Return default if exists
|
||||
$defaults = self::get_default_templates();
|
||||
return $defaults[$key] ?? null;
|
||||
|
||||
if (isset($defaults[$key])) {
|
||||
return $defaults[$key];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -57,16 +65,18 @@ class TemplateProvider {
|
||||
* @param string $event_id Event ID
|
||||
* @param string $channel_id Channel ID
|
||||
* @param array $template Template data
|
||||
* @param string $recipient_type Recipient type ('customer' or 'staff')
|
||||
* @return bool
|
||||
*/
|
||||
public static function save_template($event_id, $channel_id, $template) {
|
||||
public static function save_template($event_id, $channel_id, $template, $recipient_type = 'customer') {
|
||||
$templates = get_option(self::OPTION_KEY, []);
|
||||
|
||||
$key = "{$event_id}_{$channel_id}";
|
||||
$key = "{$recipient_type}_{$event_id}_{$channel_id}";
|
||||
|
||||
$templates[$key] = [
|
||||
'event_id' => $event_id,
|
||||
'channel_id' => $channel_id,
|
||||
'recipient_type' => $recipient_type,
|
||||
'subject' => $template['subject'] ?? '',
|
||||
'body' => $template['body'] ?? '',
|
||||
'variables' => $template['variables'] ?? [],
|
||||
@@ -81,12 +91,13 @@ class TemplateProvider {
|
||||
*
|
||||
* @param string $event_id Event ID
|
||||
* @param string $channel_id Channel ID
|
||||
* @param string $recipient_type Recipient type ('customer' or 'staff')
|
||||
* @return bool
|
||||
*/
|
||||
public static function delete_template($event_id, $channel_id) {
|
||||
public static function delete_template($event_id, $channel_id, $recipient_type = 'customer') {
|
||||
$templates = get_option(self::OPTION_KEY, []);
|
||||
|
||||
$key = "{$event_id}_{$channel_id}";
|
||||
$key = "{$recipient_type}_{$event_id}_{$channel_id}";
|
||||
|
||||
if (isset($templates[$key])) {
|
||||
unset($templates[$key]);
|
||||
@@ -130,92 +141,104 @@ class TemplateProvider {
|
||||
public static function get_default_templates() {
|
||||
$templates = [];
|
||||
|
||||
// Define all events with their recipient types
|
||||
$events = [
|
||||
'order_placed' => 'staff',
|
||||
'order_processing' => 'customer',
|
||||
'order_completed' => 'customer',
|
||||
'order_cancelled' => 'staff',
|
||||
'order_refunded' => 'customer',
|
||||
'low_stock' => 'staff',
|
||||
'out_of_stock' => 'staff',
|
||||
'new_customer' => 'customer',
|
||||
'customer_note' => 'customer',
|
||||
];
|
||||
// Get all events from EventRegistry (single source of truth)
|
||||
$all_events = EventRegistry::get_all_events();
|
||||
|
||||
// Generate email templates from DefaultEmailTemplates
|
||||
foreach ($events as $event_id => $recipient_type) {
|
||||
$default = DefaultEmailTemplates::get_template($event_id, $recipient_type);
|
||||
// Get email templates from DefaultTemplates
|
||||
$allEmailTemplates = EmailDefaultTemplates::get_all_templates();
|
||||
|
||||
foreach ($all_events as $event) {
|
||||
$event_id = $event['id'];
|
||||
$recipient_type = $event['recipient_type'];
|
||||
// Get template body from the new clean markdown source
|
||||
$body = $allEmailTemplates[$recipient_type][$event_id] ?? '';
|
||||
$subject = EmailDefaultTemplates::get_default_subject($recipient_type, $event_id);
|
||||
|
||||
$templates["{$event_id}_email"] = [
|
||||
// If template doesn't exist, create a simple fallback
|
||||
if (empty($body)) {
|
||||
$body = "[card]\n\n## Notification\n\nYou have a new notification about {$event_id}.\n\n[/card]";
|
||||
$subject = __('Notification from {store_name}', 'woonoow');
|
||||
}
|
||||
|
||||
$templates["{$recipient_type}_{$event_id}_email"] = [
|
||||
'event_id' => $event_id,
|
||||
'channel_id' => 'email',
|
||||
'subject' => $default['subject'],
|
||||
'body' => $default['body'],
|
||||
'recipient_type' => $recipient_type,
|
||||
'subject' => $subject,
|
||||
'body' => $body,
|
||||
'variables' => self::get_variables_for_event($event_id),
|
||||
];
|
||||
}
|
||||
|
||||
// Add push notification templates
|
||||
$templates['order_placed_push'] = [
|
||||
$templates['staff_order_placed_push'] = [
|
||||
'event_id' => 'order_placed',
|
||||
'channel_id' => 'push',
|
||||
'recipient_type' => 'staff',
|
||||
'subject' => __('New Order #{order_number}', 'woonoow'),
|
||||
'body' => __('New order from {customer_name} - {order_total}', 'woonoow'),
|
||||
'variables' => self::get_order_variables(),
|
||||
];
|
||||
$templates['order_processing_push'] = [
|
||||
$templates['customer_order_processing_push'] = [
|
||||
'event_id' => 'order_processing',
|
||||
'channel_id' => 'push',
|
||||
'recipient_type' => 'customer',
|
||||
'subject' => __('Order Processing', 'woonoow'),
|
||||
'body' => __('Your order #{order_number} is being processed', 'woonoow'),
|
||||
'variables' => self::get_order_variables(),
|
||||
];
|
||||
$templates['order_completed_push'] = [
|
||||
$templates['customer_order_completed_push'] = [
|
||||
'event_id' => 'order_completed',
|
||||
'channel_id' => 'push',
|
||||
'recipient_type' => 'customer',
|
||||
'subject' => __('Order Completed', 'woonoow'),
|
||||
'body' => __('Your order #{order_number} has been completed!', 'woonoow'),
|
||||
'variables' => self::get_order_variables(),
|
||||
];
|
||||
$templates['order_cancelled_push'] = [
|
||||
$templates['staff_order_cancelled_push'] = [
|
||||
'event_id' => 'order_cancelled',
|
||||
'channel_id' => 'push',
|
||||
'recipient_type' => 'staff',
|
||||
'subject' => __('Order Cancelled', 'woonoow'),
|
||||
'body' => __('Order #{order_number} has been cancelled', 'woonoow'),
|
||||
'variables' => self::get_order_variables(),
|
||||
];
|
||||
$templates['order_refunded_push'] = [
|
||||
$templates['customer_order_refunded_push'] = [
|
||||
'event_id' => 'order_refunded',
|
||||
'channel_id' => 'push',
|
||||
'recipient_type' => 'customer',
|
||||
'subject' => __('Order Refunded', 'woonoow'),
|
||||
'body' => __('Your order #{order_number} has been refunded', 'woonoow'),
|
||||
'variables' => self::get_order_variables(),
|
||||
];
|
||||
$templates['low_stock_push'] = [
|
||||
$templates['staff_low_stock_push'] = [
|
||||
'event_id' => 'low_stock',
|
||||
'channel_id' => 'push',
|
||||
'recipient_type' => 'staff',
|
||||
'subject' => __('Low Stock Alert', 'woonoow'),
|
||||
'body' => __('{product_name} is running low on stock', 'woonoow'),
|
||||
'variables' => self::get_product_variables(),
|
||||
];
|
||||
$templates['out_of_stock_push'] = [
|
||||
$templates['staff_out_of_stock_push'] = [
|
||||
'event_id' => 'out_of_stock',
|
||||
'channel_id' => 'push',
|
||||
'recipient_type' => 'staff',
|
||||
'subject' => __('Out of Stock Alert', 'woonoow'),
|
||||
'body' => __('{product_name} is now out of stock', 'woonoow'),
|
||||
'variables' => self::get_product_variables(),
|
||||
];
|
||||
$templates['new_customer_push'] = [
|
||||
$templates['customer_new_customer_push'] = [
|
||||
'event_id' => 'new_customer',
|
||||
'channel_id' => 'push',
|
||||
'recipient_type' => 'customer',
|
||||
'subject' => __('Welcome!', 'woonoow'),
|
||||
'body' => __('Welcome to {store_name}, {customer_name}!', 'woonoow'),
|
||||
'variables' => self::get_customer_variables(),
|
||||
];
|
||||
$templates['customer_note_push'] = [
|
||||
$templates['customer_customer_note_push'] = [
|
||||
'event_id' => 'customer_note',
|
||||
'channel_id' => 'push',
|
||||
'recipient_type' => 'customer',
|
||||
'subject' => __('Order Note Added', 'woonoow'),
|
||||
'body' => __('A note has been added to order #{order_number}', 'woonoow'),
|
||||
'variables' => self::get_order_variables(),
|
||||
|
||||
791
includes/Email/DefaultTemplates.php
Normal file
791
includes/Email/DefaultTemplates.php
Normal file
@@ -0,0 +1,791 @@
|
||||
<?php
|
||||
/**
|
||||
* Default Email Templates for WooNooW
|
||||
*
|
||||
* Complete collection of ready-to-use email templates for online stores.
|
||||
* These templates follow modern, minimal design principles and work perfectly
|
||||
* without any customization required by store owners.
|
||||
*
|
||||
* Card Syntax:
|
||||
* - [card] Default card with white background
|
||||
* - [card type="success"] Green-themed card for positive messages
|
||||
* - [card type="info"] Blue-themed card for information
|
||||
* - [card type="warning"] Orange-themed card for warnings
|
||||
* - [card type="hero"] Large header card with gradient background
|
||||
*
|
||||
* Button Syntax:
|
||||
* [button url="{placeholder}"]Button Text[/button]
|
||||
*
|
||||
* @package WooNooW
|
||||
* @subpackage Email
|
||||
*/
|
||||
|
||||
namespace WooNooW\Email;
|
||||
|
||||
class DefaultTemplates {
|
||||
|
||||
/**
|
||||
* Get all default templates organized by recipient and event
|
||||
*
|
||||
* @return array Associative array of templates
|
||||
*/
|
||||
public static function get_all_templates() {
|
||||
$templates = [
|
||||
'customer' => [
|
||||
'order_placed' => self::customer_order_placed(),
|
||||
'order_processing' => self::customer_order_processing(),
|
||||
'order_shipped' => self::customer_order_shipped(),
|
||||
'order_completed' => self::customer_order_completed(),
|
||||
'order_cancelled' => self::customer_order_cancelled(),
|
||||
'payment_received' => self::customer_payment_received(),
|
||||
'payment_failed' => self::customer_payment_failed(),
|
||||
'new_customer' => self::customer_new_customer(),
|
||||
],
|
||||
'staff' => [
|
||||
'order_placed' => self::staff_order_placed(),
|
||||
'order_processing' => self::staff_order_processing(),
|
||||
'order_shipped' => self::staff_order_shipped(),
|
||||
'order_completed' => self::staff_order_completed(),
|
||||
'order_cancelled' => self::staff_order_cancelled(),
|
||||
'payment_received' => self::staff_payment_received(),
|
||||
'payment_failed' => self::staff_payment_failed(),
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
* Filter: woonoow_email_default_templates
|
||||
*
|
||||
* Allows plugins to add or modify default email templates
|
||||
*
|
||||
* @param array $templates Templates organized by recipient type and event
|
||||
*/
|
||||
return apply_filters('woonoow_email_default_templates', $templates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default subject for a specific template
|
||||
*
|
||||
* @param string $recipient 'customer' or 'staff'
|
||||
* @param string $event Event type
|
||||
* @return string Default subject line
|
||||
*/
|
||||
public static function get_default_subject($recipient, $event) {
|
||||
$subjects = [
|
||||
'customer' => [
|
||||
'order_placed' => 'Your order #{order_number} has been received',
|
||||
'order_processing' => 'Your order #{order_number} is being processed',
|
||||
'order_shipped' => 'Your order #{order_number} is on its way',
|
||||
'order_completed' => 'Your order #{order_number} has arrived',
|
||||
'order_cancelled' => 'Your order #{order_number} has been cancelled',
|
||||
'payment_received' => 'Payment confirmed for order #{order_number}',
|
||||
'payment_failed' => 'Payment failed for order #{order_number}',
|
||||
'new_customer' => 'Welcome to {site_name}!',
|
||||
],
|
||||
'staff' => [
|
||||
'order_placed' => '[New Order] #{order_number} from {customer_name}',
|
||||
'order_processing' => '[Order Processing] #{order_number}',
|
||||
'order_shipped' => '[Order Shipped] #{order_number}',
|
||||
'order_completed' => '[Order Completed] #{order_number}',
|
||||
'order_cancelled' => '[Order Cancelled] #{order_number}',
|
||||
'payment_received' => '[Payment Received] #{order_number} - {order_total}',
|
||||
'payment_failed' => '[Payment Failed] #{order_number}',
|
||||
],
|
||||
];
|
||||
|
||||
$subject = $subjects[$recipient][$event] ?? '';
|
||||
|
||||
/**
|
||||
* Filter: woonoow_email_default_subject
|
||||
*
|
||||
* Allows plugins to modify default email subjects
|
||||
*
|
||||
* @param string $subject Default subject line
|
||||
* @param string $recipient Recipient type ('customer' or 'staff')
|
||||
* @param string $event Event ID
|
||||
*/
|
||||
return apply_filters('woonoow_email_default_subject', $subject, $recipient, $event);
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// CUSTOMER TEMPLATES
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* Customer: Order Placed
|
||||
* Sent immediately when customer places an order
|
||||
*/
|
||||
private static function customer_order_placed() {
|
||||
return '[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]
|
||||
|
||||
[card]
|
||||
|
||||
{order_items_table}
|
||||
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Payment Method:** {payment_method}
|
||||
**Status:** Processing
|
||||
|
||||
[/card]
|
||||
|
||||
[button url="{order_url}"]View Order Details[/button]
|
||||
|
||||
[card type="info"]
|
||||
|
||||
**What happens next?**
|
||||
|
||||
Once we confirm your payment, we\'ll prepare your order for shipment and send you a tracking number. This usually takes 1-2 business days.
|
||||
|
||||
[/card]
|
||||
|
||||
[card type="basic"]
|
||||
|
||||
Need help? Contact us: {support_email}
|
||||
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Customer: Order Processing
|
||||
* Sent when order payment is confirmed and ready for shipment
|
||||
*/
|
||||
private static function customer_order_processing() {
|
||||
return '[card type="success"]
|
||||
|
||||
## Great news, {customer_name}!
|
||||
|
||||
Your order #{order_number} is confirmed and being prepared for shipment.
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Order Number:** #{order_number}
|
||||
**Order Total:** {order_total}
|
||||
**Estimated Delivery:** 3-5 business days
|
||||
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
✓ Payment received
|
||||
✓ Order is being packed
|
||||
✓ You\'ll receive a shipping notification with tracking info
|
||||
|
||||
[/card]
|
||||
|
||||
[button url="{order_url}"]Track Your Order[/button]
|
||||
|
||||
[card type="info"]
|
||||
|
||||
Your order is on its way! You can track your shipment once we dispatch it.
|
||||
|
||||
[/card]
|
||||
|
||||
[card type="basic"]
|
||||
|
||||
Questions? We\'re here to help: {support_email}
|
||||
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Customer: Order Shipped
|
||||
* Sent when order is dispatched
|
||||
*/
|
||||
private static function customer_order_shipped() {
|
||||
return '[card type="success"]
|
||||
|
||||
## Your order #{order_number} has shipped!
|
||||
|
||||
Track your package and get real-time delivery updates.
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Tracking Number:** {tracking_number}
|
||||
**Carrier:** {shipping_carrier}
|
||||
**Estimated Delivery:** 2-3 business days
|
||||
|
||||
[/card]
|
||||
|
||||
[button url="{tracking_url}"]Track Your Package[/button]
|
||||
|
||||
[card type="info"]
|
||||
|
||||
Your package is on its way to you. Click the button above to see the current location and estimated delivery date.
|
||||
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Order Details:**
|
||||
Order #{order_number}
|
||||
{order_items_table}
|
||||
|
||||
[/card]
|
||||
|
||||
[card type="basic"]
|
||||
|
||||
Need assistance? Contact {support_email}
|
||||
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Customer: Order Completed
|
||||
* Sent when order is delivered
|
||||
*/
|
||||
private static function customer_order_completed() {
|
||||
return '[card type="success"]
|
||||
|
||||
## Your order #{order_number} has arrived!
|
||||
|
||||
We hope you love your purchase. Your feedback helps us improve.
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Order Number:** #{order_number}
|
||||
**Delivery Date:** {completion_date}
|
||||
|
||||
[/card]
|
||||
|
||||
[button url="{review_url}"]Share Your Review[/button]
|
||||
|
||||
[card type="info"]
|
||||
|
||||
Your review is valuable to us and helps other customers make informed decisions. Plus, reviewers often get special discounts on future purchases!
|
||||
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Order Summary:**
|
||||
{order_items_table}
|
||||
|
||||
[/card]
|
||||
|
||||
[card type="basic"]
|
||||
|
||||
Questions or issues with your order? We\'re here to help.
|
||||
|
||||
Contact: {support_email}
|
||||
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Customer: Order Cancelled
|
||||
* Sent when order is cancelled by customer or staff
|
||||
*/
|
||||
private static function customer_order_cancelled() {
|
||||
return '[card type="warning"]
|
||||
|
||||
## Your order #{order_number} has been cancelled.
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Order Number:** #{order_number}
|
||||
**Cancellation Date:** {order_date}
|
||||
**Order Total:** {order_total}
|
||||
|
||||
[/card]
|
||||
|
||||
[card type="info"]
|
||||
|
||||
If you made a payment, a refund will be processed to your original payment method within 5-7 business days.
|
||||
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Items:**
|
||||
{order_items_table}
|
||||
|
||||
[/card]
|
||||
|
||||
[button url="{shop_url}"]Continue Shopping[/button]
|
||||
|
||||
[card type="basic"]
|
||||
|
||||
We\'d love to know why you cancelled. Feel free to reach out to us at {support_email} if there\'s anything we can help with.
|
||||
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Customer: Payment Received
|
||||
* Sent when payment is successfully processed
|
||||
*/
|
||||
private static function customer_payment_received() {
|
||||
return '[card type="success"]
|
||||
|
||||
## Payment confirmed!
|
||||
|
||||
Thank you for your payment. Your order #{order_number} is now being processed.
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Amount Paid:** {order_total}
|
||||
**Payment Method:** {payment_method}
|
||||
**Transaction ID:** {transaction_id}
|
||||
**Date:** {payment_date}
|
||||
|
||||
[/card]
|
||||
|
||||
[card type="info"]
|
||||
|
||||
Your order is now being prepared for shipment. You\'ll receive a tracking notification within 1-2 business days.
|
||||
|
||||
[/card]
|
||||
|
||||
[button url="{order_url}"]View Your Order[/button]
|
||||
|
||||
[card]
|
||||
|
||||
Please keep this email for your records.
|
||||
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Customer: Payment Failed
|
||||
* Sent when payment processing fails
|
||||
*/
|
||||
private static function customer_payment_failed() {
|
||||
return '[card type="warning"]
|
||||
|
||||
## Payment could not be processed
|
||||
|
||||
We were unable to complete the payment for order #{order_number}. Your order is still reserved, but we need you to update your payment information.
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Order Number:** #{order_number}
|
||||
**Order Total:** {order_total}
|
||||
**Reason:** Payment declined
|
||||
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Common reasons:**
|
||||
• Insufficient funds
|
||||
• Incorrect card details
|
||||
• Card expired or blocked
|
||||
• Bank security check
|
||||
|
||||
[/card]
|
||||
|
||||
[button url="{payment_retry_url}"]Update Payment Method[/button]
|
||||
|
||||
[card type="info"]
|
||||
|
||||
Your order is on hold. Please update your payment information to proceed. If you continue to experience issues, contact your bank or reach out to us.
|
||||
|
||||
[/card]
|
||||
|
||||
[card type="basic"]
|
||||
|
||||
Questions? {support_email}
|
||||
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Customer: New Customer
|
||||
* Sent when customer creates an account
|
||||
*/
|
||||
private static function customer_new_customer() {
|
||||
return '[card type="hero"]
|
||||
|
||||
# Welcome to {site_name}, {customer_name}!
|
||||
|
||||
Your account is ready. Let\'s get you started.
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Account Benefits:**
|
||||
✓ Faster checkout on your next order
|
||||
✓ Order history and tracking
|
||||
✓ Exclusive member offers and updates
|
||||
✓ Wishlist and saved items
|
||||
✓ Easy returns and exchanges
|
||||
|
||||
[/card]
|
||||
|
||||
[button url="{my_account_url}"]Access Your Account[/button]
|
||||
|
||||
[button url="{shop_url}"]Start Shopping[/button]
|
||||
|
||||
[card type="info"]
|
||||
|
||||
We\'re excited to have you as part of our community. Happy shopping!
|
||||
|
||||
[/card]
|
||||
|
||||
[card type="basic"]
|
||||
|
||||
Need help? Contact {support_email}
|
||||
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Customer: VIP Upgraded
|
||||
* Sent when customer is upgraded to VIP status
|
||||
*/
|
||||
private static function customer_vip_upgraded() {
|
||||
return '[card type="success"]
|
||||
|
||||
## Congratulations, {customer_name}!
|
||||
|
||||
You\'re now a VIP member.
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Your VIP Perks:**
|
||||
✓ Exclusive early access to new products
|
||||
✓ Special VIP-only discounts
|
||||
✓ Priority customer support
|
||||
✓ Free shipping on orders over {vip_free_shipping_threshold}
|
||||
✓ Birthday month bonus gift
|
||||
|
||||
[/card]
|
||||
|
||||
[button url="{vip_dashboard_url}"]View Your VIP Dashboard[/button]
|
||||
|
||||
[card type="info"]
|
||||
|
||||
Simply shop as usual—your VIP benefits are automatically applied to all your orders. Thank you for your continued loyalty!
|
||||
|
||||
[/card]
|
||||
|
||||
[card type="basic"]
|
||||
|
||||
Questions? {support_email}
|
||||
|
||||
[/card]';
|
||||
}
|
||||
|
||||
// ========================================================================
|
||||
// STAFF TEMPLATES
|
||||
// ========================================================================
|
||||
|
||||
/**
|
||||
* Staff: Order Placed
|
||||
* Notifies staff when customer places an order
|
||||
*/
|
||||
private static function staff_order_placed() {
|
||||
return '[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}
|
||||
**Order Total:** {order_total}
|
||||
**Payment Status:** {payment_status}
|
||||
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Customer Contact:**
|
||||
Email: {customer_email}
|
||||
Phone: {customer_phone}
|
||||
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Items Ordered:**
|
||||
{order_items_table}
|
||||
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Delivery Address:**
|
||||
{shipping_address}
|
||||
|
||||
[/card]
|
||||
|
||||
[button url="{order_url}"]Process This Order[/button]
|
||||
|
||||
[card type="info"]
|
||||
|
||||
If payment status is "pending", please follow up with the customer or wait for payment confirmation before processing.
|
||||
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Staff: Order Processing
|
||||
* Notifies staff when order is confirmed and ready to process
|
||||
*/
|
||||
private static function staff_order_processing() {
|
||||
return '[card type="success"]
|
||||
|
||||
## Order confirmed and ready to process
|
||||
|
||||
Order #{order_number} is confirmed. Payment has been received. Begin preparation.
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Order Number:** #{order_number}
|
||||
**Customer:** {customer_name}
|
||||
**Order Total:** {order_total}
|
||||
**Confirmed Date:** {order_date}
|
||||
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Items to Prepare:**
|
||||
{order_items_table}
|
||||
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Action Items:**
|
||||
• Verify inventory and pick items
|
||||
• Quality check
|
||||
• Pack securely
|
||||
• Generate shipping label
|
||||
• Update order status when shipped
|
||||
|
||||
[/card]
|
||||
|
||||
[button url="{order_url}"]View Full Order[/button]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Staff: Order Shipped
|
||||
* Notifies staff when order is marked as shipped
|
||||
*/
|
||||
private static function staff_order_shipped() {
|
||||
return '[card type="success"]
|
||||
|
||||
## Order shipped
|
||||
|
||||
Order #{order_number} has been dispatched. Customer notified with tracking info.
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Order Number:** #{order_number}
|
||||
**Customer:** {customer_name}
|
||||
**Tracking Number:** {tracking_number}
|
||||
**Carrier:** {shipping_carrier}
|
||||
**Shipped Date:** {order_date}
|
||||
|
||||
[/card]
|
||||
|
||||
[button url="{order_url}"]View Order[/button]
|
||||
|
||||
[card type="info"]
|
||||
|
||||
Customer has been automatically notified via email with tracking details.
|
||||
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Staff: Order Completed
|
||||
* Notifies staff when order is completed/delivered
|
||||
*/
|
||||
private static function staff_order_completed() {
|
||||
return '[card type="success"]
|
||||
|
||||
## Order completed
|
||||
|
||||
Order #{order_number} has been delivered to customer. All steps completed.
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Order Number:** #{order_number}
|
||||
**Customer:** {customer_name}
|
||||
**Order Total:** {order_total}
|
||||
**Completed Date:** {order_date}
|
||||
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Order Timeline:**
|
||||
✓ Order placed
|
||||
✓ Payment received
|
||||
✓ Order prepared and packed
|
||||
✓ Shipped
|
||||
✓ Delivered
|
||||
|
||||
[/card]
|
||||
|
||||
[button url="{order_url}"]View Order[/button]
|
||||
|
||||
[card type="info"]
|
||||
|
||||
Customer has been notified and invited to leave a review.
|
||||
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Staff: Order Cancelled
|
||||
* Notifies staff when order is cancelled
|
||||
*/
|
||||
private static function staff_order_cancelled() {
|
||||
return '[card type="warning"]
|
||||
|
||||
## Order cancelled
|
||||
|
||||
Order #{order_number} has been cancelled. Please process refund if payment was received.
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Order Number:** #{order_number}
|
||||
**Customer:** {customer_name}
|
||||
**Order Total:** {order_total}
|
||||
**Cancelled Date:** {order_date}
|
||||
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Items (will not ship):**
|
||||
{order_items_table}
|
||||
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Action Items:**
|
||||
• If payment received: Process refund to original payment method
|
||||
• Update inventory for cancelled items
|
||||
• Check warehouse if order was already being prepared
|
||||
• Confirm cancellation with customer
|
||||
|
||||
[/card]
|
||||
|
||||
[button url="{order_url}"]View Order & Process Refund[/button]
|
||||
|
||||
[card type="info"]
|
||||
|
||||
Customer has been notified of the cancellation.
|
||||
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Staff: Payment Received
|
||||
* Notifies staff when payment is successfully received
|
||||
*/
|
||||
private static function staff_payment_received() {
|
||||
return '[card type="success"]
|
||||
|
||||
## Payment received
|
||||
|
||||
Payment has been successfully processed for order #{order_number}. Ready to begin order processing.
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Order Number:** #{order_number}
|
||||
**Customer:** {customer_name}
|
||||
**Amount:** {order_total}
|
||||
**Payment Method:** {payment_method}
|
||||
**Transaction ID:** {transaction_id}
|
||||
**Date:** {payment_date}
|
||||
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Next Steps:**
|
||||
• Confirm the order
|
||||
• Begin item preparation
|
||||
• Prepare shipping label
|
||||
• Update customer with tracking info
|
||||
|
||||
[/card]
|
||||
|
||||
[button url="{order_url}"]Process Order[/button]
|
||||
|
||||
[card type="info"]
|
||||
|
||||
Order is now confirmed and ready for fulfillment.
|
||||
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Staff: Payment Failed
|
||||
* Notifies staff when payment processing fails
|
||||
*/
|
||||
private static function staff_payment_failed() {
|
||||
return '[card type="warning"]
|
||||
|
||||
## Payment failed
|
||||
|
||||
Payment processing failed for order #{order_number}. Order is on hold pending payment.
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Order Number:** #{order_number}
|
||||
**Customer:** {customer_name}
|
||||
**Amount:** {order_total}
|
||||
**Payment Method:** {payment_method}
|
||||
**Failed Date:** {payment_date}
|
||||
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
|
||||
**Action Items:**
|
||||
• Customer has been notified to update payment
|
||||
• Check order status after 24 hours
|
||||
• If still unpaid, consider cancelling
|
||||
• Contact customer if needed
|
||||
|
||||
[/card]
|
||||
|
||||
[button url="{order_url}"]View Order Details[/button]
|
||||
|
||||
[card type="info"]
|
||||
|
||||
Order is reserved but will be cancelled automatically if payment is not received within 24-48 hours (configure this in settings).
|
||||
|
||||
[/card]';
|
||||
}
|
||||
}
|
||||
709
includes/Email/DefaultTemplates_Old.php
Normal file
709
includes/Email/DefaultTemplates_Old.php
Normal file
@@ -0,0 +1,709 @@
|
||||
<?php
|
||||
/**
|
||||
* Default Email Templates for WooNooW
|
||||
*
|
||||
* This file contains default email content templates for all notification types.
|
||||
* These templates are used when a store is first installed, providing ready-to-use
|
||||
* email content so merchants can start selling immediately.
|
||||
*
|
||||
* Template Structure:
|
||||
* - Each template is organized by recipient (customer/staff) and event type
|
||||
* - Templates use [card] shortcode syntax for visual blocks
|
||||
* - Variables are wrapped in curly braces: {variable_name}
|
||||
* - Card types: default, success, info, warning, hero
|
||||
*
|
||||
* Available Variables by Event:
|
||||
*
|
||||
* ORDER EVENTS (order_placed, order_confirmed, order_shipped, order_completed, order_cancelled):
|
||||
* - {customer_name} - Customer's full name
|
||||
* - {order_number} - Order number/ID
|
||||
* - {order_date} - Order creation date
|
||||
* - {order_total} - Total order amount
|
||||
* - {order_url} - Link to view order details
|
||||
* - {order_items} - List of ordered items
|
||||
* - {payment_method} - Payment method used
|
||||
* - {shipping_address} - Full shipping address
|
||||
* - {billing_address} - Full billing address
|
||||
* - {tracking_number} - Shipping tracking number (if available)
|
||||
* - {tracking_url} - Tracking URL (if available)
|
||||
*
|
||||
* PAYMENT EVENTS (payment_received, payment_failed):
|
||||
* - All order variables above, plus:
|
||||
* - {payment_status} - Current payment status
|
||||
* - {payment_date} - Payment date/time
|
||||
* - {transaction_id} - Payment transaction ID
|
||||
*
|
||||
* CUSTOMER EVENTS (customer_registered, customer_vip_upgraded):
|
||||
* - {customer_name} - Customer's full name
|
||||
* - {customer_email} - Customer's email
|
||||
* - {account_url} - Link to customer account
|
||||
* - {vip_benefits} - List of VIP benefits (for vip_upgraded)
|
||||
*
|
||||
* COMMON VARIABLES (available in all templates):
|
||||
* - {site_name} - Store name
|
||||
* - {site_url} - Store URL
|
||||
* - {support_email} - Support email address
|
||||
* - {current_year} - Current year (for copyright)
|
||||
*
|
||||
* Card Syntax Examples:
|
||||
*
|
||||
* [card]
|
||||
* <h2>Simple Card</h2>
|
||||
* <p>Default card with white background</p>
|
||||
* [/card]
|
||||
*
|
||||
* [card type="success"]
|
||||
* <h2>Success Card</h2>
|
||||
* <p>Green-themed card for positive messages</p>
|
||||
* [/card]
|
||||
*
|
||||
* [card type="hero"]
|
||||
* <h2>Hero Card</h2>
|
||||
* <p>Large header card with gradient background</p>
|
||||
* [/card]
|
||||
*
|
||||
* Button Syntax:
|
||||
* <p style="text-align: center;"><a href="{order_url}" class="button">View Order</a></p>
|
||||
* <p style="text-align: center;"><a href="{order_url}" class="button-outline">View Order</a></p>
|
||||
*
|
||||
* @package WooNooW
|
||||
* @subpackage Email
|
||||
*/
|
||||
|
||||
namespace WooNooW\Email;
|
||||
|
||||
class DefaultTemplates {
|
||||
|
||||
/**
|
||||
* Get all default templates organized by recipient and event
|
||||
*
|
||||
* @return array Associative array of templates
|
||||
*/
|
||||
public static function get_all_templates() {
|
||||
return [
|
||||
'customer' => [
|
||||
'order_placed' => self::customer_order_placed(),
|
||||
'order_confirmed' => self::customer_order_confirmed(),
|
||||
'order_shipped' => self::customer_order_shipped(),
|
||||
'order_completed' => self::customer_order_completed(),
|
||||
'order_cancelled' => self::customer_order_cancelled(),
|
||||
'payment_received' => self::customer_payment_received(),
|
||||
'payment_failed' => self::customer_payment_failed(),
|
||||
'customer_registered' => self::customer_registered(),
|
||||
'customer_vip_upgraded' => self::customer_vip_upgraded(),
|
||||
],
|
||||
'staff' => [
|
||||
'order_placed' => self::staff_order_placed(),
|
||||
'order_confirmed' => self::staff_order_confirmed(),
|
||||
'order_shipped' => self::staff_order_shipped(),
|
||||
'order_completed' => self::staff_order_completed(),
|
||||
'order_cancelled' => self::staff_order_cancelled(),
|
||||
'payment_received' => self::staff_payment_received(),
|
||||
'payment_failed' => self::staff_payment_failed(),
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default subject for a specific template
|
||||
*
|
||||
* @param string $recipient 'customer' or 'staff'
|
||||
* @param string $event Event type
|
||||
* @return string Default subject line
|
||||
*/
|
||||
public static function get_default_subject($recipient, $event) {
|
||||
$subjects = [
|
||||
'customer' => [
|
||||
'order_placed' => 'Order Received - #{order_number}',
|
||||
'order_confirmed' => 'Order Confirmed - #{order_number}',
|
||||
'order_shipped' => 'Your Order Has Shipped - #{order_number}',
|
||||
'order_completed' => 'Order Delivered - #{order_number}',
|
||||
'order_cancelled' => 'Order Cancelled - #{order_number}',
|
||||
'payment_received' => 'Payment Received - #{order_number}',
|
||||
'payment_failed' => 'Payment Failed - #{order_number}',
|
||||
'customer_registered' => 'Welcome to {site_name}!',
|
||||
'customer_vip_upgraded' => 'You\'re Now a VIP Member!',
|
||||
],
|
||||
'staff' => [
|
||||
'order_placed' => '[New Order] #{order_number} from {customer_name}',
|
||||
'order_confirmed' => '[Order Confirmed] #{order_number}',
|
||||
'order_shipped' => '[Order Shipped] #{order_number}',
|
||||
'order_completed' => '[Order Completed] #{order_number}',
|
||||
'order_cancelled' => '[Order Cancelled] #{order_number}',
|
||||
'payment_received' => '[Payment Received] #{order_number}',
|
||||
'payment_failed' => '[Payment Failed] #{order_number}',
|
||||
],
|
||||
];
|
||||
|
||||
return $subjects[$recipient][$event] ?? '';
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// CUSTOMER TEMPLATES
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Customer: Order Placed
|
||||
* Sent immediately when customer places an order
|
||||
*/
|
||||
private static function customer_order_placed() {
|
||||
return '[card type="hero"]
|
||||
<h1>Order Received!</h1>
|
||||
<p>Thank you for your order, {customer_name}. We\'ve received your order and will process it shortly.</p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<h2>Order Details</h2>
|
||||
<p><strong>Order Number:</strong> #{order_number}</p>
|
||||
<p><strong>Order Date:</strong> {order_date}</p>
|
||||
<p><strong>Order Total:</strong> {order_total}</p>
|
||||
<p><strong>Payment Method:</strong> {payment_method}</p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<h3>Items Ordered</h3>
|
||||
{order_items}
|
||||
[/card]
|
||||
|
||||
[card type="info"]
|
||||
<h3>Shipping Address</h3>
|
||||
{shipping_address}
|
||||
[/card]
|
||||
|
||||
<p style="text-align: center;"><a href="{order_url}" class="button">View Order Details</a></p>
|
||||
|
||||
[card]
|
||||
<p style="text-align: center; color: #666; font-size: 14px;">
|
||||
Need help? Contact us at {support_email}<br>
|
||||
© {current_year} {site_name}. All rights reserved.
|
||||
</p>
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Customer: Order Confirmed
|
||||
* Sent when staff confirms the order
|
||||
*/
|
||||
private static function customer_order_confirmed() {
|
||||
return '[card type="success"]
|
||||
<h1>Order Confirmed!</h1>
|
||||
<p>Great news, {customer_name}! Your order #{order_number} has been confirmed and is being prepared for shipment.</p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<h2>Order Summary</h2>
|
||||
<p><strong>Order Number:</strong> #{order_number}</p>
|
||||
<p><strong>Order Total:</strong> {order_total}</p>
|
||||
<p><strong>Estimated Delivery:</strong> 3-5 business days</p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<h3>What\'s Next?</h3>
|
||||
<p>✓ Your order is being carefully prepared</p>
|
||||
<p>✓ You\'ll receive a shipping notification with tracking info</p>
|
||||
<p>✓ Track your order anytime using the link below</p>
|
||||
[/card]
|
||||
|
||||
<p style="text-align: center;"><a href="{order_url}" class="button">Track Your Order</a></p>
|
||||
|
||||
[card]
|
||||
<p style="text-align: center; color: #666; font-size: 14px;">
|
||||
Questions? We\'re here to help at {support_email}<br>
|
||||
© {current_year} {site_name}
|
||||
</p>
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Customer: Order Shipped
|
||||
* Sent when order is marked as shipped
|
||||
*/
|
||||
private static function customer_order_shipped() {
|
||||
return '[card type="hero"]
|
||||
<h1>Your Order is On Its Way!</h1>
|
||||
<p>Good news, {customer_name}! Your order #{order_number} has been shipped and is heading your way.</p>
|
||||
[/card]
|
||||
|
||||
[card type="info"]
|
||||
<h2>Tracking Information</h2>
|
||||
<p><strong>Tracking Number:</strong> {tracking_number}</p>
|
||||
<p><strong>Carrier:</strong> Standard Shipping</p>
|
||||
<p><strong>Estimated Delivery:</strong> 2-3 business days</p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<h3>Shipping To:</h3>
|
||||
{shipping_address}
|
||||
[/card]
|
||||
|
||||
<p style="text-align: center;"><a href="{tracking_url}" class="button">Track Your Package</a></p>
|
||||
|
||||
[card]
|
||||
<p style="text-align: center; color: #666; font-size: 14px;">
|
||||
Need assistance? Contact {support_email}<br>
|
||||
© {current_year} {site_name}
|
||||
</p>
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Customer: Order Completed
|
||||
* Sent when order is marked as completed/delivered
|
||||
*/
|
||||
private static function customer_order_completed() {
|
||||
return '[card type="success"]
|
||||
<h1>Order Delivered!</h1>
|
||||
<p>Your order #{order_number} has been successfully delivered. We hope you love your purchase!</p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<h2>How Was Your Experience?</h2>
|
||||
<p>We\'d love to hear your feedback! Your review helps us improve and helps other customers make informed decisions.</p>
|
||||
[/card]
|
||||
|
||||
<p style="text-align: center;"><a href="{order_url}" class="button">Leave a Review</a></p>
|
||||
|
||||
[card type="info"]
|
||||
<h3>Need Support?</h3>
|
||||
<p>If you have any questions or concerns about your order, our support team is ready to help.</p>
|
||||
<p style="text-align: center;"><a href="mailto:{support_email}" class="button-outline">Contact Support</a></p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<p style="text-align: center; color: #666; font-size: 14px;">
|
||||
Thank you for shopping with us!<br>
|
||||
© {current_year} {site_name}
|
||||
</p>
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Customer: Order Cancelled
|
||||
* Sent when order is cancelled
|
||||
*/
|
||||
private static function customer_order_cancelled() {
|
||||
return '[card type="warning"]
|
||||
<h1>Order Cancelled</h1>
|
||||
<p>Your order #{order_number} has been cancelled as requested.</p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<h2>Cancellation Details</h2>
|
||||
<p><strong>Order Number:</strong> #{order_number}</p>
|
||||
<p><strong>Order Total:</strong> {order_total}</p>
|
||||
<p><strong>Cancellation Date:</strong> {order_date}</p>
|
||||
[/card]
|
||||
|
||||
[card type="info"]
|
||||
<h3>Refund Information</h3>
|
||||
<p>If you\'ve already made a payment, a refund will be processed to your original payment method within 5-7 business days.</p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<h3>Changed Your Mind?</h3>
|
||||
<p>You can always place a new order anytime. We\'re here whenever you need us!</p>
|
||||
<p style="text-align: center;"><a href="{site_url}" class="button">Continue Shopping</a></p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<p style="text-align: center; color: #666; font-size: 14px;">
|
||||
Questions? Contact {support_email}<br>
|
||||
© {current_year} {site_name}
|
||||
</p>
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Customer: Payment Received
|
||||
* Sent when payment is successfully processed
|
||||
*/
|
||||
private static function customer_payment_received() {
|
||||
return '[card type="success"]
|
||||
<h1>Payment Received!</h1>
|
||||
<p>Thank you, {customer_name}! We\'ve received your payment for order #{order_number}.</p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<h2>Payment Details</h2>
|
||||
<p><strong>Amount Paid:</strong> {order_total}</p>
|
||||
<p><strong>Payment Method:</strong> {payment_method}</p>
|
||||
<p><strong>Transaction ID:</strong> {transaction_id}</p>
|
||||
<p><strong>Payment Date:</strong> {payment_date}</p>
|
||||
[/card]
|
||||
|
||||
[card type="info"]
|
||||
<h3>What\'s Next?</h3>
|
||||
<p>Your order is now being processed and will be shipped soon. You\'ll receive a shipping notification with tracking information.</p>
|
||||
[/card]
|
||||
|
||||
<p style="text-align: center;"><a href="{order_url}" class="button">View Order</a></p>
|
||||
|
||||
[card]
|
||||
<p style="text-align: center; color: #666; font-size: 14px;">
|
||||
Keep this email for your records<br>
|
||||
© {current_year} {site_name}
|
||||
</p>
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Customer: Payment Failed
|
||||
* Sent when payment processing fails
|
||||
*/
|
||||
private static function customer_payment_failed() {
|
||||
return '[card type="warning"]
|
||||
<h1>Payment Issue</h1>
|
||||
<p>We were unable to process your payment for order #{order_number}.</p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<h2>What Happened?</h2>
|
||||
<p>Your payment could not be completed. This can happen for several reasons:</p>
|
||||
<p>• Insufficient funds</p>
|
||||
<p>• Incorrect card details</p>
|
||||
<p>• Card expired or blocked</p>
|
||||
<p>• Bank security check</p>
|
||||
[/card]
|
||||
|
||||
[card type="info"]
|
||||
<h3>How to Fix This</h3>
|
||||
<p>Please update your payment information and try again. Your order is still reserved for you.</p>
|
||||
<p style="text-align: center;"><a href="{order_url}" class="button">Update Payment Method</a></p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<h3>Need Help?</h3>
|
||||
<p>If you continue to experience issues, please contact your bank or reach out to our support team.</p>
|
||||
<p>Email: {support_email}</p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<p style="text-align: center; color: #666; font-size: 14px;">
|
||||
© {current_year} {site_name}
|
||||
</p>
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Customer: Account Registered
|
||||
* Sent when customer creates an account
|
||||
*/
|
||||
private static function customer_registered() {
|
||||
return '[card type="hero"]
|
||||
<h1>Welcome to {site_name}!</h1>
|
||||
<p>Hi {customer_name}, we\'re thrilled to have you join our community!</p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<h2>Your Account is Ready</h2>
|
||||
<p>You can now enjoy all the benefits of being a registered member:</p>
|
||||
<p>✓ Faster checkout process</p>
|
||||
<p>✓ Order history and tracking</p>
|
||||
<p>✓ Exclusive member offers</p>
|
||||
<p>✓ Wishlist and favorites</p>
|
||||
<p>✓ Easy returns and exchanges</p>
|
||||
[/card]
|
||||
|
||||
<p style="text-align: center;"><a href="{account_url}" class="button">Go to My Account</a></p>
|
||||
|
||||
[card type="success"]
|
||||
<h3>Start Shopping!</h3>
|
||||
<p>Browse our latest products and discover amazing deals just for you.</p>
|
||||
<p style="text-align: center;"><a href="{site_url}" class="button-outline">Start Shopping</a></p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<p style="text-align: center; color: #666; font-size: 14px;">
|
||||
Need help? We\'re here for you at {support_email}<br>
|
||||
© {current_year} {site_name}
|
||||
</p>
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Customer: VIP Upgraded
|
||||
* Sent when customer is upgraded to VIP status
|
||||
*/
|
||||
private static function customer_vip_upgraded() {
|
||||
return '[card type="hero"]
|
||||
<h1>🎉 You\'re Now a VIP!</h1>
|
||||
<p>Congratulations, {customer_name}! You\'ve been upgraded to VIP status.</p>
|
||||
[/card]
|
||||
|
||||
[card type="success"]
|
||||
<h2>Your VIP Benefits</h2>
|
||||
{vip_benefits}
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<h3>How to Use Your Benefits</h3>
|
||||
<p>Your VIP perks are automatically applied to your account. Simply shop as usual and enjoy your exclusive benefits!</p>
|
||||
[/card]
|
||||
|
||||
<p style="text-align: center;"><a href="{account_url}" class="button">View My VIP Dashboard</a></p>
|
||||
|
||||
[card type="info"]
|
||||
<h3>Thank You for Your Loyalty</h3>
|
||||
<p>We truly appreciate your continued support. As a VIP member, you\'re part of our most valued customer group.</p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<p style="text-align: center; color: #666; font-size: 14px;">
|
||||
Questions about your VIP status? Contact {support_email}<br>
|
||||
© {current_year} {site_name}
|
||||
</p>
|
||||
[/card]';
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// STAFF TEMPLATES
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Staff: New Order Placed
|
||||
* Notifies staff when a new order is received
|
||||
*/
|
||||
private static function staff_order_placed() {
|
||||
return '[card type="info"]
|
||||
<h1>New Order Received</h1>
|
||||
<p>A new order has been placed by {customer_name}.</p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<h2>Order Information</h2>
|
||||
<p><strong>Order Number:</strong> #{order_number}</p>
|
||||
<p><strong>Customer:</strong> {customer_name}</p>
|
||||
<p><strong>Order Date:</strong> {order_date}</p>
|
||||
<p><strong>Order Total:</strong> {order_total}</p>
|
||||
<p><strong>Payment Method:</strong> {payment_method}</p>
|
||||
<p><strong>Payment Status:</strong> {payment_status}</p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<h3>Items Ordered</h3>
|
||||
{order_items}
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<h3>Shipping Address</h3>
|
||||
{shipping_address}
|
||||
[/card]
|
||||
|
||||
<p style="text-align: center;"><a href="{order_url}" class="button">Process Order</a></p>
|
||||
|
||||
[card]
|
||||
<p style="text-align: center; color: #666; font-size: 14px;">
|
||||
WooNooW Order Notification<br>
|
||||
© {current_year} {site_name}
|
||||
</p>
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Staff: Order Confirmed
|
||||
* Notifies staff when order is confirmed
|
||||
*/
|
||||
private static function staff_order_confirmed() {
|
||||
return '[card type="success"]
|
||||
<h1>Order Confirmed</h1>
|
||||
<p>Order #{order_number} has been confirmed and is ready for processing.</p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<h2>Order Details</h2>
|
||||
<p><strong>Order Number:</strong> #{order_number}</p>
|
||||
<p><strong>Customer:</strong> {customer_name}</p>
|
||||
<p><strong>Order Total:</strong> {order_total}</p>
|
||||
<p><strong>Confirmed Date:</strong> {order_date}</p>
|
||||
[/card]
|
||||
|
||||
[card type="info"]
|
||||
<h3>Next Steps</h3>
|
||||
<p>• Prepare items for shipment</p>
|
||||
<p>• Update inventory</p>
|
||||
<p>• Generate shipping label</p>
|
||||
<p>• Mark as shipped when ready</p>
|
||||
[/card]
|
||||
|
||||
<p style="text-align: center;"><a href="{order_url}" class="button">View Order</a></p>
|
||||
|
||||
[card]
|
||||
<p style="text-align: center; color: #666; font-size: 14px;">
|
||||
WooNooW Order Notification
|
||||
</p>
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Staff: Order Shipped
|
||||
* Notifies staff when order is shipped
|
||||
*/
|
||||
private static function staff_order_shipped() {
|
||||
return '[card type="success"]
|
||||
<h1>Order Shipped</h1>
|
||||
<p>Order #{order_number} has been marked as shipped.</p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<h2>Shipment Details</h2>
|
||||
<p><strong>Order Number:</strong> #{order_number}</p>
|
||||
<p><strong>Customer:</strong> {customer_name}</p>
|
||||
<p><strong>Tracking Number:</strong> {tracking_number}</p>
|
||||
<p><strong>Shipped Date:</strong> {order_date}</p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<h3>Shipping Address</h3>
|
||||
{shipping_address}
|
||||
[/card]
|
||||
|
||||
<p style="text-align: center;"><a href="{order_url}" class="button">View Order</a></p>
|
||||
|
||||
[card]
|
||||
<p style="text-align: center; color: #666; font-size: 14px;">
|
||||
Customer has been notified via email
|
||||
</p>
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Staff: Order Completed
|
||||
* Notifies staff when order is completed
|
||||
*/
|
||||
private static function staff_order_completed() {
|
||||
return '[card type="success"]
|
||||
<h1>Order Completed</h1>
|
||||
<p>Order #{order_number} has been marked as completed.</p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<h2>Order Summary</h2>
|
||||
<p><strong>Order Number:</strong> #{order_number}</p>
|
||||
<p><strong>Customer:</strong> {customer_name}</p>
|
||||
<p><strong>Order Total:</strong> {order_total}</p>
|
||||
<p><strong>Completion Date:</strong> {order_date}</p>
|
||||
[/card]
|
||||
|
||||
[card type="info"]
|
||||
<h3>Order Lifecycle Complete</h3>
|
||||
<p>✓ Order placed</p>
|
||||
<p>✓ Payment received</p>
|
||||
<p>✓ Order shipped</p>
|
||||
<p>✓ Delivered to customer</p>
|
||||
[/card]
|
||||
|
||||
<p style="text-align: center;"><a href="{order_url}" class="button">View Order</a></p>
|
||||
|
||||
[card]
|
||||
<p style="text-align: center; color: #666; font-size: 14px;">
|
||||
Customer has been notified
|
||||
</p>
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Staff: Order Cancelled
|
||||
* Notifies staff when order is cancelled
|
||||
*/
|
||||
private static function staff_order_cancelled() {
|
||||
return '[card type="warning"]
|
||||
<h1>Order Cancelled</h1>
|
||||
<p>Order #{order_number} has been cancelled.</p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<h2>Cancellation Details</h2>
|
||||
<p><strong>Order Number:</strong> #{order_number}</p>
|
||||
<p><strong>Customer:</strong> {customer_name}</p>
|
||||
<p><strong>Order Total:</strong> {order_total}</p>
|
||||
<p><strong>Cancellation Date:</strong> {order_date}</p>
|
||||
[/card]
|
||||
|
||||
[card type="info"]
|
||||
<h3>Action Required</h3>
|
||||
<p>• Process refund if payment was received</p>
|
||||
<p>• Update inventory</p>
|
||||
<p>• Notify warehouse if order was being prepared</p>
|
||||
[/card]
|
||||
|
||||
<p style="text-align: center;"><a href="{order_url}" class="button">View Order</a></p>
|
||||
|
||||
[card]
|
||||
<p style="text-align: center; color: #666; font-size: 14px;">
|
||||
Customer has been notified
|
||||
</p>
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Staff: Payment Received
|
||||
* Notifies staff when payment is received
|
||||
*/
|
||||
private static function staff_payment_received() {
|
||||
return '[card type="success"]
|
||||
<h1>Payment Received</h1>
|
||||
<p>Payment has been received for order #{order_number}.</p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<h2>Payment Details</h2>
|
||||
<p><strong>Order Number:</strong> #{order_number}</p>
|
||||
<p><strong>Customer:</strong> {customer_name}</p>
|
||||
<p><strong>Amount:</strong> {order_total}</p>
|
||||
<p><strong>Payment Method:</strong> {payment_method}</p>
|
||||
<p><strong>Transaction ID:</strong> {transaction_id}</p>
|
||||
<p><strong>Payment Date:</strong> {payment_date}</p>
|
||||
[/card]
|
||||
|
||||
[card type="info"]
|
||||
<h3>Next Steps</h3>
|
||||
<p>• Confirm the order</p>
|
||||
<p>• Begin order processing</p>
|
||||
<p>• Prepare for shipment</p>
|
||||
[/card]
|
||||
|
||||
<p style="text-align: center;"><a href="{order_url}" class="button">Process Order</a></p>
|
||||
|
||||
[card]
|
||||
<p style="text-align: center; color: #666; font-size: 14px;">
|
||||
Customer has been notified
|
||||
</p>
|
||||
[/card]';
|
||||
}
|
||||
|
||||
/**
|
||||
* Staff: Payment Failed
|
||||
* Notifies staff when payment fails
|
||||
*/
|
||||
private static function staff_payment_failed() {
|
||||
return '[card type="warning"]
|
||||
<h1>Payment Failed</h1>
|
||||
<p>Payment processing failed for order #{order_number}.</p>
|
||||
[/card]
|
||||
|
||||
[card]
|
||||
<h2>Order Details</h2>
|
||||
<p><strong>Order Number:</strong> #{order_number}</p>
|
||||
<p><strong>Customer:</strong> {customer_name}</p>
|
||||
<p><strong>Order Total:</strong> {order_total}</p>
|
||||
<p><strong>Payment Method:</strong> {payment_method}</p>
|
||||
<p><strong>Failed Date:</strong> {payment_date}</p>
|
||||
[/card]
|
||||
|
||||
[card type="info"]
|
||||
<h3>Action Required</h3>
|
||||
<p>• Customer has been notified</p>
|
||||
<p>• Order is on hold pending payment</p>
|
||||
<p>• Follow up with customer if needed</p>
|
||||
<p>• Consider cancelling if payment not received within 24 hours</p>
|
||||
[/card]
|
||||
|
||||
<p style="text-align: center;"><a href="{order_url}" class="button">View Order</a></p>
|
||||
|
||||
[card]
|
||||
<p style="text-align: center; color: #666; font-size: 14px;">
|
||||
WooNooW Payment Notification
|
||||
</p>
|
||||
[/card]';
|
||||
}
|
||||
}
|
||||
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