finalizing subscription moduile, ready to test
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Email Renderer
|
||||
*
|
||||
@@ -9,70 +10,75 @@
|
||||
|
||||
namespace WooNooW\Core\Notifications;
|
||||
|
||||
class EmailRenderer {
|
||||
|
||||
|
||||
|
||||
class EmailRenderer
|
||||
{
|
||||
|
||||
/**
|
||||
* Instance
|
||||
*/
|
||||
private static $instance = null;
|
||||
|
||||
|
||||
/**
|
||||
* Get instance
|
||||
*/
|
||||
public static function instance() {
|
||||
public static function instance()
|
||||
{
|
||||
if (null === self::$instance) {
|
||||
self::$instance = new self();
|
||||
}
|
||||
return self::$instance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Render email
|
||||
*
|
||||
* @param string $event_id Event ID (order_placed, order_processing, etc.)
|
||||
* @param string $recipient_type Recipient type (staff, customer)
|
||||
* @param mixed $data Order, Product, or Customer object
|
||||
* @param WC_Order|WC_Product|WC_Customer|mixed $data Order, Product, or Customer object
|
||||
* @param array $extra_data Additional data
|
||||
* @return array|null ['to', 'subject', 'body']
|
||||
*/
|
||||
public function render($event_id, $recipient_type, $data, $extra_data = []) {
|
||||
public function render($event_id, $recipient_type, $data, $extra_data = [])
|
||||
{
|
||||
// Get template settings
|
||||
$template_settings = $this->get_template_settings($event_id, $recipient_type);
|
||||
|
||||
|
||||
if (!$template_settings) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// Get recipient email
|
||||
$to = $this->get_recipient_email($recipient_type, $data);
|
||||
|
||||
|
||||
if (!$to) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// Get variables
|
||||
$variables = $this->get_variables($event_id, $data, $extra_data);
|
||||
|
||||
|
||||
// Replace variables in subject and content
|
||||
$subject = $this->replace_variables($template_settings['subject'], $variables);
|
||||
$content = $this->replace_variables($template_settings['body'], $variables);
|
||||
|
||||
|
||||
// Parse cards in content
|
||||
$content = $this->parse_cards($content);
|
||||
|
||||
|
||||
// Get HTML template
|
||||
$template_path = $this->get_design_template();
|
||||
|
||||
|
||||
// Render final HTML
|
||||
$html = $this->render_html($template_path, $content, $subject, $variables);
|
||||
|
||||
|
||||
return [
|
||||
'to' => $to,
|
||||
'subject' => $subject,
|
||||
'body' => $html,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get template settings
|
||||
*
|
||||
@@ -80,30 +86,31 @@ class EmailRenderer {
|
||||
* @param string $recipient_type
|
||||
* @return array|null
|
||||
*/
|
||||
private function get_template_settings($event_id, $recipient_type) {
|
||||
private function get_template_settings($event_id, $recipient_type)
|
||||
{
|
||||
// Get saved template (with recipient_type for proper default template lookup)
|
||||
$template = TemplateProvider::get_template($event_id, 'email', $recipient_type);
|
||||
|
||||
|
||||
if (!$template) {
|
||||
if (defined('WP_DEBUG') && WP_DEBUG) {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
if (defined('WP_DEBUG') && WP_DEBUG) {
|
||||
}
|
||||
|
||||
|
||||
// Get design template preference
|
||||
$settings = get_option('woonoow_notification_settings', []);
|
||||
$design = $settings['email_design_template'] ?? 'modern';
|
||||
|
||||
|
||||
return [
|
||||
'subject' => $template['subject'] ?? '',
|
||||
'body' => $template['body'] ?? '',
|
||||
'design' => $design,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get recipient email
|
||||
*
|
||||
@@ -111,23 +118,24 @@ class EmailRenderer {
|
||||
* @param mixed $data
|
||||
* @return string|null
|
||||
*/
|
||||
private function get_recipient_email($recipient_type, $data) {
|
||||
private function get_recipient_email($recipient_type, $data)
|
||||
{
|
||||
if ($recipient_type === 'staff') {
|
||||
return get_option('admin_email');
|
||||
}
|
||||
|
||||
|
||||
// Customer
|
||||
if ($data instanceof \WC_Order) {
|
||||
if ($data instanceof WC_Order) {
|
||||
return $data->get_billing_email();
|
||||
}
|
||||
|
||||
if ($data instanceof \WC_Customer) {
|
||||
|
||||
if ($data instanceof WC_Customer) {
|
||||
return $data->get_email();
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get variables for template
|
||||
*
|
||||
@@ -136,7 +144,8 @@ class EmailRenderer {
|
||||
* @param array $extra_data
|
||||
* @return array
|
||||
*/
|
||||
private function get_variables($event_id, $data, $extra_data = []) {
|
||||
private function get_variables($event_id, $data, $extra_data = [])
|
||||
{
|
||||
$variables = [
|
||||
'site_name' => get_bloginfo('name'),
|
||||
'site_title' => get_bloginfo('name'),
|
||||
@@ -147,12 +156,12 @@ class EmailRenderer {
|
||||
'support_email' => get_option('admin_email'),
|
||||
'current_year' => date('Y'),
|
||||
];
|
||||
|
||||
|
||||
// Order variables
|
||||
if ($data instanceof \WC_Order) {
|
||||
if ($data instanceof WC_Order) {
|
||||
// Calculate estimated delivery (3-5 business days from now)
|
||||
$estimated_delivery = date('F j', strtotime('+3 days')) . '-' . date('j', strtotime('+5 days'));
|
||||
|
||||
|
||||
// Completion date (for completed orders)
|
||||
$completion_date = '';
|
||||
if ($data->get_date_completed()) {
|
||||
@@ -160,13 +169,13 @@ class EmailRenderer {
|
||||
} else {
|
||||
$completion_date = date('F j, Y'); // Fallback to today
|
||||
}
|
||||
|
||||
|
||||
// Payment date
|
||||
$payment_date = '';
|
||||
if ($data->get_date_paid()) {
|
||||
$payment_date = $data->get_date_paid()->date('F j, Y');
|
||||
}
|
||||
|
||||
|
||||
$variables = array_merge($variables, [
|
||||
'order_number' => $data->get_order_number(),
|
||||
'order_id' => $data->get_id(),
|
||||
@@ -202,7 +211,7 @@ class EmailRenderer {
|
||||
'tracking_url' => $data->get_meta('_tracking_url') ?: '#',
|
||||
'shipping_carrier' => $data->get_meta('_shipping_carrier') ?: 'Standard Shipping',
|
||||
]);
|
||||
|
||||
|
||||
// Order items table
|
||||
$items_html = '<table class="order-details" style="width: 100%; border-collapse: collapse;">';
|
||||
$items_html .= '<thead><tr>';
|
||||
@@ -210,7 +219,7 @@ class EmailRenderer {
|
||||
$items_html .= '<th style="text-align: center; padding: 12px 0; border-bottom: 1px solid #e5e5e5;">Qty</th>';
|
||||
$items_html .= '<th style="text-align: right; padding: 12px 0; border-bottom: 1px solid #e5e5e5;">Price</th>';
|
||||
$items_html .= '</tr></thead><tbody>';
|
||||
|
||||
|
||||
foreach ($data->get_items() as $item) {
|
||||
$product = $item->get_product();
|
||||
$items_html .= '<tr>';
|
||||
@@ -228,16 +237,16 @@ class EmailRenderer {
|
||||
);
|
||||
$items_html .= '</tr>';
|
||||
}
|
||||
|
||||
|
||||
$items_html .= '</tbody></table>';
|
||||
|
||||
|
||||
// Both naming conventions for compatibility
|
||||
$variables['order_items'] = $items_html;
|
||||
$variables['order_items_table'] = $items_html;
|
||||
}
|
||||
|
||||
|
||||
// Product variables
|
||||
if ($data instanceof \WC_Product) {
|
||||
if ($data instanceof WC_Product) {
|
||||
$variables = array_merge($variables, [
|
||||
'product_id' => $data->get_id(),
|
||||
'product_name' => $data->get_name(),
|
||||
@@ -248,27 +257,27 @@ class EmailRenderer {
|
||||
'stock_status' => $data->get_stock_status(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
// Customer variables
|
||||
if ($data instanceof \WC_Customer) {
|
||||
if ($data instanceof WC_Customer) {
|
||||
// Get temp password from user meta (stored during auto-registration)
|
||||
$user_temp_password = get_user_meta($data->get_id(), '_woonoow_temp_password', true);
|
||||
|
||||
|
||||
// Generate login URL (pointing to SPA login instead of wp-login)
|
||||
$appearance_settings = get_option('woonoow_appearance_settings', []);
|
||||
$spa_page_id = $appearance_settings['general']['spa_page'] ?? 0;
|
||||
$use_browser_router = $appearance_settings['general']['use_browser_router'] ?? true;
|
||||
|
||||
|
||||
if ($spa_page_id) {
|
||||
$spa_url = get_permalink($spa_page_id);
|
||||
// Use path format for BrowserRouter, hash format for HashRouter
|
||||
$login_url = $use_browser_router
|
||||
$login_url = $use_browser_router
|
||||
? trailingslashit($spa_url) . 'login'
|
||||
: $spa_url . '#/login';
|
||||
} else {
|
||||
$login_url = wp_login_url();
|
||||
}
|
||||
|
||||
|
||||
$variables = array_merge($variables, [
|
||||
'customer_id' => $data->get_id(),
|
||||
'customer_name' => $data->get_display_name(),
|
||||
@@ -282,31 +291,32 @@ class EmailRenderer {
|
||||
'shop_url' => get_permalink(wc_get_page_id('shop')),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
// Merge extra data
|
||||
$variables = array_merge($variables, $extra_data);
|
||||
|
||||
|
||||
return apply_filters('woonoow_email_variables', $variables, $event_id, $data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse [card] tags and convert to HTML
|
||||
*
|
||||
* @param string $content
|
||||
* @return string
|
||||
*/
|
||||
private function parse_cards($content) {
|
||||
private function parse_cards($content)
|
||||
{
|
||||
// Use a single unified regex to match BOTH syntaxes in document order
|
||||
// This ensures cards are rendered in the order they appear
|
||||
$combined_pattern = '/\[card(?::(\w+)|([^\]]*)?)\](.*?)\[\/card\]/s';
|
||||
|
||||
|
||||
preg_match_all($combined_pattern, $content, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE);
|
||||
|
||||
|
||||
if (empty($matches)) {
|
||||
// No cards found, wrap entire content in a single card
|
||||
return $this->render_card($content, []);
|
||||
}
|
||||
|
||||
|
||||
$html = '';
|
||||
foreach ($matches as $match) {
|
||||
// Determine which syntax was matched
|
||||
@@ -314,7 +324,7 @@ class EmailRenderer {
|
||||
$new_syntax_type = !empty($match[1][0]) ? $match[1][0] : null; // [card:type] format
|
||||
$old_syntax_attrs = $match[2][0] ?? ''; // [card type="..."] format
|
||||
$card_content = $match[3][0];
|
||||
|
||||
|
||||
if ($new_syntax_type) {
|
||||
// NEW syntax [card:type]
|
||||
$attributes = ['type' => $new_syntax_type];
|
||||
@@ -322,42 +332,43 @@ class EmailRenderer {
|
||||
// OLD syntax [card type="..."] or [card]
|
||||
$attributes = $this->parse_card_attributes($old_syntax_attrs);
|
||||
}
|
||||
|
||||
|
||||
$html .= $this->render_card($card_content, $attributes);
|
||||
$html .= $this->render_card_spacing();
|
||||
}
|
||||
|
||||
|
||||
// Remove last spacing
|
||||
$html = preg_replace('/<table[^>]*class="card-spacing"[^>]*>.*?<\/table>\s*$/s', '', $html);
|
||||
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse card attributes from [card ...] tag
|
||||
*
|
||||
* @param string $attr_string
|
||||
* @return array
|
||||
*/
|
||||
private function parse_card_attributes($attr_string) {
|
||||
private function parse_card_attributes($attr_string)
|
||||
{
|
||||
$attributes = [
|
||||
'type' => 'default',
|
||||
'bg' => null,
|
||||
];
|
||||
|
||||
|
||||
// Parse type="highlight"
|
||||
if (preg_match('/type=["\']([^"\']+)["\']/', $attr_string, $match)) {
|
||||
$attributes['type'] = $match[1];
|
||||
}
|
||||
|
||||
|
||||
// Parse bg="url"
|
||||
if (preg_match('/bg=["\']([^"\']+)["\']/', $attr_string, $match)) {
|
||||
$attributes['bg'] = $match[1];
|
||||
}
|
||||
|
||||
|
||||
return $attributes;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Render a single card
|
||||
*
|
||||
@@ -365,13 +376,14 @@ class EmailRenderer {
|
||||
* @param array $attributes
|
||||
* @return string
|
||||
*/
|
||||
private function render_card($content, $attributes) {
|
||||
private function render_card($content, $attributes)
|
||||
{
|
||||
$type = $attributes['type'] ?? 'default';
|
||||
$bg = $attributes['bg'] ?? null;
|
||||
|
||||
|
||||
// Parse markdown in content
|
||||
$content = MarkdownParser::parse($content);
|
||||
|
||||
|
||||
// Get email customization settings for colors
|
||||
// Use unified colors from Appearance > General > Colors
|
||||
$appearance = get_option('woonoow_appearance_settings', []);
|
||||
@@ -382,10 +394,10 @@ class EmailRenderer {
|
||||
$hero_gradient_start = $colors['gradientStart'] ?? '#667eea';
|
||||
$hero_gradient_end = $colors['gradientEnd'] ?? '#764ba2';
|
||||
$hero_text_color = '#ffffff'; // Always white on gradient
|
||||
|
||||
|
||||
// Parse button shortcodes with FULL INLINE STYLES for Gmail compatibility
|
||||
// Helper function to generate button HTML
|
||||
$generateButtonHtml = function($url, $style, $text) use ($primary_color, $secondary_color, $button_text_color) {
|
||||
$generateButtonHtml = function ($url, $style, $text) use ($primary_color, $secondary_color, $button_text_color) {
|
||||
if ($style === 'outline') {
|
||||
// Outline button - transparent background with border
|
||||
$button_style = sprintf(
|
||||
@@ -401,7 +413,7 @@ class EmailRenderer {
|
||||
esc_attr($button_text_color)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Use table-based button for better email client compatibility
|
||||
return sprintf(
|
||||
'<table role="presentation" border="0" cellpadding="0" cellspacing="0" style="margin: 16px auto;"><tr><td align="center"><a href="%s" style="%s">%s</a></td></tr></table>',
|
||||
@@ -410,11 +422,11 @@ class EmailRenderer {
|
||||
esc_html($text)
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
// NEW FORMAT: [button:style](url)Text[/button]
|
||||
$content = preg_replace_callback(
|
||||
'/\[button:(\w+)\]\(([^)]+)\)([^\[]+)\[\/button\]/',
|
||||
function($matches) use ($generateButtonHtml) {
|
||||
function ($matches) use ($generateButtonHtml) {
|
||||
$style = $matches[1]; // solid or outline
|
||||
$url = $matches[2];
|
||||
$text = trim($matches[3]);
|
||||
@@ -422,11 +434,11 @@ class EmailRenderer {
|
||||
},
|
||||
$content
|
||||
);
|
||||
|
||||
|
||||
// OLD FORMAT: [button url="..." style="solid|outline"]Text[/button]
|
||||
$content = preg_replace_callback(
|
||||
'/\[button\s+url=["\']([^"\']+)["\'](?:\s+style=["\'](solid|outline)["\'])?\]([^\[]+)\[\/button\]/',
|
||||
function($matches) use ($generateButtonHtml) {
|
||||
function ($matches) use ($generateButtonHtml) {
|
||||
$url = $matches[1];
|
||||
$style = $matches[2] ?? 'solid';
|
||||
$text = trim($matches[3]);
|
||||
@@ -434,15 +446,15 @@ class EmailRenderer {
|
||||
},
|
||||
$content
|
||||
);
|
||||
|
||||
|
||||
$class = 'card';
|
||||
$style = 'width: 100%; background-color: #ffffff; border-radius: 8px;';
|
||||
$content_style = 'padding: 32px 40px;';
|
||||
|
||||
|
||||
// Add type class and styling
|
||||
if ($type !== 'default') {
|
||||
$class .= ' card-' . esc_attr($type);
|
||||
|
||||
|
||||
// Apply gradient and text color for hero cards
|
||||
if ($type === 'hero') {
|
||||
$style .= sprintf(
|
||||
@@ -451,7 +463,7 @@ class EmailRenderer {
|
||||
esc_attr($hero_gradient_end)
|
||||
);
|
||||
$content_style .= sprintf(' color: %s;', esc_attr($hero_text_color));
|
||||
|
||||
|
||||
// Add inline color to all headings and paragraphs for email client compatibility
|
||||
$content = preg_replace(
|
||||
'/<(h[1-6]|p)([^>]*)>/',
|
||||
@@ -472,13 +484,13 @@ class EmailRenderer {
|
||||
$style .= ' background-color: #fff8e1;';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Add background image
|
||||
if ($bg) {
|
||||
$class .= ' card-bg';
|
||||
$style .= ' background-image: url(' . esc_url($bg) . ');';
|
||||
}
|
||||
|
||||
|
||||
return sprintf(
|
||||
'<table role="presentation" class="%s" border="0" cellpadding="0" cellspacing="0" style="%s">
|
||||
<tr>
|
||||
@@ -493,18 +505,19 @@ class EmailRenderer {
|
||||
$content
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Render card spacing
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function render_card_spacing() {
|
||||
private function render_card_spacing()
|
||||
{
|
||||
return '<table role="presentation" border="0" cellpadding="0" cellspacing="0" width="100%">
|
||||
<tr><td class="card-spacing" style="height: 24px; font-size: 24px; line-height: 24px;"> </td></tr>
|
||||
</table>';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Replace variables in text
|
||||
*
|
||||
@@ -512,34 +525,36 @@ class EmailRenderer {
|
||||
* @param array $variables
|
||||
* @return string
|
||||
*/
|
||||
private function replace_variables($text, $variables) {
|
||||
private function replace_variables($text, $variables)
|
||||
{
|
||||
foreach ($variables as $key => $value) {
|
||||
$text = str_replace('{' . $key . '}', $value, $text);
|
||||
}
|
||||
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get design template path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function get_design_template() {
|
||||
private function get_design_template()
|
||||
{
|
||||
// Use single base template (theme-agnostic)
|
||||
$template_path = WOONOOW_PATH . 'templates/emails/base.html';
|
||||
|
||||
|
||||
// Allow filtering template path
|
||||
$template_path = apply_filters('woonoow_email_template', $template_path);
|
||||
|
||||
|
||||
// Fallback to base if custom template doesn't exist
|
||||
if (!file_exists($template_path)) {
|
||||
$template_path = WOONOOW_PATH . 'templates/emails/base.html';
|
||||
}
|
||||
|
||||
|
||||
return $template_path;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Render HTML email
|
||||
*
|
||||
@@ -549,29 +564,30 @@ class EmailRenderer {
|
||||
* @param array $variables All variables
|
||||
* @return string
|
||||
*/
|
||||
private function render_html($template_path, $content, $subject, $variables) {
|
||||
private function render_html($template_path, $content, $subject, $variables)
|
||||
{
|
||||
if (!file_exists($template_path)) {
|
||||
// Fallback to plain HTML
|
||||
return $content;
|
||||
}
|
||||
|
||||
|
||||
// Load template
|
||||
$html = file_get_contents($template_path);
|
||||
|
||||
|
||||
// Get email customization settings
|
||||
$email_settings = get_option('woonoow_email_settings', []);
|
||||
|
||||
|
||||
// Email body background
|
||||
$body_bg = '#f8f8f8';
|
||||
|
||||
|
||||
// Email header (logo or text)
|
||||
$logo_url = $email_settings['logo_url'] ?? '';
|
||||
|
||||
|
||||
// Fallback to site icon if no logo set
|
||||
if (empty($logo_url) && has_site_icon()) {
|
||||
$logo_url = get_site_icon_url(200);
|
||||
}
|
||||
|
||||
|
||||
if (!empty($logo_url)) {
|
||||
$header = sprintf(
|
||||
'<a href="%s"><img src="%s" alt="%s" style="max-width: 200px; max-height: 60px;"></a>',
|
||||
@@ -588,17 +604,17 @@ class EmailRenderer {
|
||||
esc_html($header_text)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Email footer with {current_year} variable support
|
||||
$footer_text = !empty($email_settings['footer_text']) ? $email_settings['footer_text'] : sprintf(
|
||||
'© %s %s. All rights reserved.',
|
||||
date('Y'),
|
||||
$variables['store_name']
|
||||
);
|
||||
|
||||
|
||||
// Replace {current_year} with actual year
|
||||
$footer_text = str_replace('{current_year}', date('Y'), $footer_text);
|
||||
|
||||
|
||||
// Social icons with PNG images
|
||||
$social_html = '';
|
||||
if (!empty($email_settings['social_links']) && is_array($email_settings['social_links'])) {
|
||||
@@ -617,13 +633,13 @@ class EmailRenderer {
|
||||
}
|
||||
$social_html .= '</div>';
|
||||
}
|
||||
|
||||
|
||||
$footer = sprintf(
|
||||
'<p style="font-family: \'Inter\', Arial, sans-serif; font-size: 13px; line-height: 1.5; color: #888888; margin: 0 0 8px 0; text-align: center;">%s</p>%s',
|
||||
nl2br(esc_html($footer_text)),
|
||||
$social_html
|
||||
);
|
||||
|
||||
|
||||
// Replace placeholders
|
||||
$html = str_replace('{{email_subject}}', esc_html($subject), $html);
|
||||
$html = str_replace('{{email_body_bg}}', esc_attr($body_bg), $html);
|
||||
@@ -633,15 +649,15 @@ class EmailRenderer {
|
||||
$html = str_replace('{{store_name}}', esc_html($variables['store_name']), $html);
|
||||
$html = str_replace('{{store_url}}', esc_url($variables['store_url']), $html);
|
||||
$html = str_replace('{{current_year}}', date('Y'), $html);
|
||||
|
||||
|
||||
// Replace all other variables
|
||||
foreach ($variables as $key => $value) {
|
||||
$html = str_replace('{{' . $key . '}}', $value, $html);
|
||||
}
|
||||
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get social icon URL
|
||||
*
|
||||
@@ -649,7 +665,8 @@ class EmailRenderer {
|
||||
* @param string $color 'white' or 'black'
|
||||
* @return string
|
||||
*/
|
||||
private function get_social_icon_url($platform, $color = 'white') {
|
||||
private function get_social_icon_url($platform, $color = 'white')
|
||||
{
|
||||
// Use plugin URL constant if available, otherwise calculate from file path
|
||||
if (defined('WOONOOW_URL')) {
|
||||
$plugin_url = WOONOOW_URL;
|
||||
|
||||
375
includes/Core/Notifications/TemplateProvider.bak.php
Normal file
375
includes/Core/Notifications/TemplateProvider.bak.php
Normal file
@@ -0,0 +1,375 @@
|
||||
<?php
|
||||
/**
|
||||
* Notification Template Provider
|
||||
*
|
||||
* Manages notification templates for all channels.
|
||||
*
|
||||
* @package WooNooW\Core\Notifications
|
||||
*/
|
||||
|
||||
namespace WooNooW\Core\Notifications;
|
||||
|
||||
use WooNooW\Email\DefaultTemplates as EmailDefaultTemplates;
|
||||
|
||||
class TemplateProvider {
|
||||
|
||||
/**
|
||||
* Option key for storing templates
|
||||
*/
|
||||
const OPTION_KEY = 'woonoow_notification_templates';
|
||||
|
||||
/**
|
||||
* Get all templates
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_templates() {
|
||||
$templates = get_option(self::OPTION_KEY, []);
|
||||
|
||||
// Merge with defaults
|
||||
$defaults = self::get_default_templates();
|
||||
|
||||
return array_merge($defaults, $templates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get template for specific event and channel
|
||||
*
|
||||
* @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, $recipient_type = 'customer') {
|
||||
$templates = self::get_templates();
|
||||
|
||||
$key = "{$recipient_type}_{$event_id}_{$channel_id}";
|
||||
|
||||
if (isset($templates[$key])) {
|
||||
return $templates[$key];
|
||||
}
|
||||
|
||||
// Return default if exists
|
||||
$defaults = self::get_default_templates();
|
||||
|
||||
if (isset($defaults[$key])) {
|
||||
return $defaults[$key];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save template
|
||||
*
|
||||
* @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, $recipient_type = 'customer') {
|
||||
$templates = get_option(self::OPTION_KEY, []);
|
||||
|
||||
$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'] ?? [],
|
||||
'updated_at' => current_time('mysql'),
|
||||
];
|
||||
|
||||
return update_option(self::OPTION_KEY, $templates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete template (revert to default)
|
||||
*
|
||||
* @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, $recipient_type = 'customer') {
|
||||
$templates = get_option(self::OPTION_KEY, []);
|
||||
|
||||
$key = "{$recipient_type}_{$event_id}_{$channel_id}";
|
||||
|
||||
if (isset($templates[$key])) {
|
||||
unset($templates[$key]);
|
||||
return update_option(self::OPTION_KEY, $templates);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get WooCommerce email template content
|
||||
*
|
||||
* @param string $email_id WooCommerce email ID
|
||||
* @return array|null
|
||||
*/
|
||||
private static function get_wc_email_template($email_id) {
|
||||
if (!function_exists('WC')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$mailer = \WC()->mailer();
|
||||
$emails = $mailer->get_emails();
|
||||
|
||||
if (isset($emails[$email_id])) {
|
||||
$email = $emails[$email_id];
|
||||
return [
|
||||
'subject' => $email->get_subject(),
|
||||
'heading' => $email->get_heading(),
|
||||
'enabled' => $email->is_enabled(),
|
||||
];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default templates
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_default_templates() {
|
||||
$templates = [];
|
||||
|
||||
// Get all events from EventRegistry (single source of truth)
|
||||
$all_events = EventRegistry::get_all_events();
|
||||
|
||||
// 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);
|
||||
|
||||
// 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',
|
||||
'recipient_type' => $recipient_type,
|
||||
'subject' => $subject,
|
||||
'body' => $body,
|
||||
'variables' => self::get_variables_for_event($event_id),
|
||||
];
|
||||
}
|
||||
|
||||
// Add push notification templates
|
||||
$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['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['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['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['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['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['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['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_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(),
|
||||
];
|
||||
|
||||
return $templates;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get variables for a specific event
|
||||
*
|
||||
* @param string $event_id Event ID
|
||||
* @return array
|
||||
*/
|
||||
private static function get_variables_for_event($event_id) {
|
||||
// Product events
|
||||
if (in_array($event_id, ['low_stock', 'out_of_stock'])) {
|
||||
return self::get_product_variables();
|
||||
}
|
||||
|
||||
// Customer events (but not order-related)
|
||||
if ($event_id === 'new_customer') {
|
||||
return self::get_customer_variables();
|
||||
}
|
||||
|
||||
// Subscription events
|
||||
if (strpos($event_id, 'subscription_') === 0) {
|
||||
return self::get_subscription_variables();
|
||||
}
|
||||
|
||||
// All other events are order-related
|
||||
return self::get_order_variables();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available order variables
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_order_variables() {
|
||||
return [
|
||||
'order_number' => __('Order Number', 'woonoow'),
|
||||
'order_total' => __('Order Total', 'woonoow'),
|
||||
'order_status' => __('Order Status', 'woonoow'),
|
||||
'order_date' => __('Order Date', 'woonoow'),
|
||||
'order_url' => __('Order URL', 'woonoow'),
|
||||
'order_items_list' => __('Order Items (formatted list)', 'woonoow'),
|
||||
'order_items_table' => __('Order Items (formatted table)', 'woonoow'),
|
||||
'payment_method' => __('Payment Method', 'woonoow'),
|
||||
'payment_url' => __('Payment URL (for pending payments)', 'woonoow'),
|
||||
'shipping_method' => __('Shipping Method', 'woonoow'),
|
||||
'tracking_number' => __('Tracking Number', 'woonoow'),
|
||||
'refund_amount' => __('Refund Amount', 'woonoow'),
|
||||
'customer_name' => __('Customer Name', 'woonoow'),
|
||||
'customer_email' => __('Customer Email', 'woonoow'),
|
||||
'customer_phone' => __('Customer Phone', 'woonoow'),
|
||||
'billing_address' => __('Billing Address', 'woonoow'),
|
||||
'shipping_address' => __('Shipping Address', 'woonoow'),
|
||||
'store_name' => __('Store Name', 'woonoow'),
|
||||
'store_url' => __('Store URL', 'woonoow'),
|
||||
'store_email' => __('Store Email', 'woonoow'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available product variables
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_product_variables() {
|
||||
return [
|
||||
'product_name' => __('Product Name', 'woonoow'),
|
||||
'product_sku' => __('Product SKU', 'woonoow'),
|
||||
'product_url' => __('Product URL', 'woonoow'),
|
||||
'stock_quantity' => __('Stock Quantity', 'woonoow'),
|
||||
'store_name' => __('Store Name', 'woonoow'),
|
||||
'store_url' => __('Store URL', 'woonoow'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available customer variables
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_customer_variables() {
|
||||
return [
|
||||
'customer_name' => __('Customer Name', 'woonoow'),
|
||||
'customer_email' => __('Customer Email', 'woonoow'),
|
||||
'customer_phone' => __('Customer Phone', 'woonoow'),
|
||||
'store_name' => __('Store Name', 'woonoow'),
|
||||
'store_url' => __('Store URL', 'woonoow'),
|
||||
'store_email' => __('Store Email', 'woonoow'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available subscription variables
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscription_variables() {
|
||||
return [
|
||||
'subscription_id' => __('Subscription ID', 'woonoow'),
|
||||
'subscription_status' => __('Subscription Status', 'woonoow'),
|
||||
'product_name' => __('Product Name', 'woonoow'),
|
||||
'billing_period' => __('Billing Period (e.g., Monthly)', 'woonoow'),
|
||||
'recurring_amount' => __('Recurring Amount', 'woonoow'),
|
||||
'next_payment_date' => __('Next Payment Date', 'woonoow'),
|
||||
'end_date' => __('Subscription End Date', 'woonoow'),
|
||||
'cancel_reason' => __('Cancellation Reason', 'woonoow'),
|
||||
'customer_name' => __('Customer Name', 'woonoow'),
|
||||
'customer_email' => __('Customer Email', 'woonoow'),
|
||||
'store_name' => __('Store Name', 'woonoow'),
|
||||
'store_url' => __('Store URL', 'woonoow'),
|
||||
'my_account_url' => __('My Account URL', 'woonoow'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace variables in template
|
||||
*
|
||||
* @param string $content Content with variables
|
||||
* @param array $data Data to replace variables
|
||||
* @return string
|
||||
*/
|
||||
public static function replace_variables($content, $data) {
|
||||
foreach ($data as $key => $value) {
|
||||
$content = str_replace('{' . $key . '}', $value, $content);
|
||||
}
|
||||
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
@@ -107,32 +107,6 @@ class TemplateProvider {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get WooCommerce email template content
|
||||
*
|
||||
* @param string $email_id WooCommerce email ID
|
||||
* @return array|null
|
||||
*/
|
||||
private static function get_wc_email_template($email_id) {
|
||||
if (!function_exists('WC')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$mailer = WC()->mailer();
|
||||
$emails = $mailer->get_emails();
|
||||
|
||||
if (isset($emails[$email_id])) {
|
||||
$email = $emails[$email_id];
|
||||
return [
|
||||
'subject' => $email->get_subject(),
|
||||
'heading' => $email->get_heading(),
|
||||
'enabled' => $email->is_enabled(),
|
||||
];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get default templates
|
||||
*
|
||||
@@ -264,6 +238,11 @@ class TemplateProvider {
|
||||
return self::get_customer_variables();
|
||||
}
|
||||
|
||||
// Subscription events
|
||||
if (strpos($event_id, 'subscription_') === 0) {
|
||||
return self::get_subscription_variables();
|
||||
}
|
||||
|
||||
// All other events are order-related
|
||||
return self::get_order_variables();
|
||||
}
|
||||
@@ -330,6 +309,29 @@ class TemplateProvider {
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get available subscription variables
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function get_subscription_variables() {
|
||||
return [
|
||||
'subscription_id' => __('Subscription ID', 'woonoow'),
|
||||
'subscription_status' => __('Subscription Status', 'woonoow'),
|
||||
'product_name' => __('Product Name', 'woonoow'),
|
||||
'billing_period' => __('Billing Period (e.g., Monthly)', 'woonoow'),
|
||||
'recurring_amount' => __('Recurring Amount', 'woonoow'),
|
||||
'next_payment_date' => __('Next Payment Date', 'woonoow'),
|
||||
'end_date' => __('Subscription End Date', 'woonoow'),
|
||||
'cancel_reason' => __('Cancellation Reason', 'woonoow'),
|
||||
'customer_name' => __('Customer Name', 'woonoow'),
|
||||
'customer_email' => __('Customer Email', 'woonoow'),
|
||||
'store_name' => __('Store Name', 'woonoow'),
|
||||
'store_url' => __('Store URL', 'woonoow'),
|
||||
'my_account_url' => __('My Account URL', 'woonoow'),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Replace variables in template
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user