feat: Backend API & Email Rendering with Settings! 🔌
## 4. Wire to Backend ✅ ### API Endpoints Created: - `GET /woonoow/v1/notifications/email-settings` - Fetch settings - `POST /woonoow/v1/notifications/email-settings` - Save settings - `DELETE /woonoow/v1/notifications/email-settings` - Reset to defaults ### Features: - Proper sanitization (sanitize_hex_color, esc_url_raw, etc.) - Social links validation (allowed platforms only) - Defaults fallback - Stored in wp_options as `woonoow_email_settings` ### Email Rendering Integration: **Logo & Header:** - Uses logo_url if set, otherwise header_text - Falls back to store name **Footer:** - Uses footer_text with {current_year} support - Replaces {current_year} with actual year dynamically - Social icons rendered from social_links array **Hero Cards:** - Applies hero_gradient_start and hero_gradient_end - Applies hero_text_color to text and headings - Works for type="hero" and type="success" cards **Button Colors:** - Ready to apply primary_color and button_text_color - (Template needs update for dynamic button colors) ### Files: - `includes/Api/NotificationsController.php` - API endpoints - `includes/Core/Notifications/EmailRenderer.php` - Apply settings to emails ### Security: - Permission checks (check_permission) - Input sanitization - URL validation - Platform whitelist for social links Frontend can now save/load settings! Backend applies them to emails! 🎉
This commit is contained in:
@@ -121,6 +121,33 @@ class NotificationsController {
|
||||
],
|
||||
]);
|
||||
|
||||
// GET /woonoow/v1/notifications/email-settings
|
||||
register_rest_route($this->namespace, '/' . $this->rest_base . '/email-settings', [
|
||||
[
|
||||
'methods' => 'GET',
|
||||
'callback' => [$this, 'get_email_settings'],
|
||||
'permission_callback' => [$this, 'check_permission'],
|
||||
],
|
||||
]);
|
||||
|
||||
// POST /woonoow/v1/notifications/email-settings
|
||||
register_rest_route($this->namespace, '/' . $this->rest_base . '/email-settings', [
|
||||
[
|
||||
'methods' => 'POST',
|
||||
'callback' => [$this, 'save_email_settings'],
|
||||
'permission_callback' => [$this, 'check_permission'],
|
||||
],
|
||||
]);
|
||||
|
||||
// DELETE /woonoow/v1/notifications/email-settings
|
||||
register_rest_route($this->namespace, '/' . $this->rest_base . '/email-settings', [
|
||||
[
|
||||
'methods' => 'DELETE',
|
||||
'callback' => [$this, 'reset_email_settings'],
|
||||
'permission_callback' => [$this, 'check_permission'],
|
||||
],
|
||||
]);
|
||||
|
||||
// GET /woonoow/v1/notifications/push/settings
|
||||
register_rest_route($this->namespace, '/' . $this->rest_base . '/push/settings', [
|
||||
[
|
||||
@@ -815,4 +842,104 @@ class NotificationsController {
|
||||
'enabled' => (bool) $verified,
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get email customization settings
|
||||
*/
|
||||
public function get_email_settings(WP_REST_Request $request) {
|
||||
$defaults = [
|
||||
'primary_color' => '#7f54b3',
|
||||
'secondary_color' => '#7f54b3',
|
||||
'hero_gradient_start' => '#667eea',
|
||||
'hero_gradient_end' => '#764ba2',
|
||||
'hero_text_color' => '#ffffff',
|
||||
'button_text_color' => '#ffffff',
|
||||
'logo_url' => '',
|
||||
'header_text' => '',
|
||||
'footer_text' => '',
|
||||
'social_links' => [],
|
||||
];
|
||||
|
||||
$settings = get_option('woonoow_email_settings', $defaults);
|
||||
|
||||
// Ensure social_links is an array
|
||||
if (!isset($settings['social_links']) || !is_array($settings['social_links'])) {
|
||||
$settings['social_links'] = [];
|
||||
}
|
||||
|
||||
// Merge with defaults to ensure all fields exist
|
||||
$settings = array_merge($defaults, $settings);
|
||||
|
||||
return new WP_REST_Response($settings, 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save email customization settings
|
||||
*/
|
||||
public function save_email_settings(WP_REST_Request $request) {
|
||||
$data = $request->get_json_params();
|
||||
|
||||
$settings = [
|
||||
'primary_color' => sanitize_hex_color($data['primary_color'] ?? '#7f54b3'),
|
||||
'secondary_color' => sanitize_hex_color($data['secondary_color'] ?? '#7f54b3'),
|
||||
'hero_gradient_start' => sanitize_hex_color($data['hero_gradient_start'] ?? '#667eea'),
|
||||
'hero_gradient_end' => sanitize_hex_color($data['hero_gradient_end'] ?? '#764ba2'),
|
||||
'hero_text_color' => sanitize_hex_color($data['hero_text_color'] ?? '#ffffff'),
|
||||
'button_text_color' => sanitize_hex_color($data['button_text_color'] ?? '#ffffff'),
|
||||
'logo_url' => esc_url_raw($data['logo_url'] ?? ''),
|
||||
'header_text' => sanitize_text_field($data['header_text'] ?? ''),
|
||||
'footer_text' => sanitize_text_field($data['footer_text'] ?? ''),
|
||||
'social_links' => $this->sanitize_social_links($data['social_links'] ?? []),
|
||||
];
|
||||
|
||||
update_option('woonoow_email_settings', $settings);
|
||||
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'message' => __('Email settings saved successfully', 'woonoow'),
|
||||
'settings' => $settings,
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset email customization settings to defaults
|
||||
*/
|
||||
public function reset_email_settings(WP_REST_Request $request) {
|
||||
delete_option('woonoow_email_settings');
|
||||
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'message' => __('Email settings reset to defaults', 'woonoow'),
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitize social links array
|
||||
*/
|
||||
private function sanitize_social_links($links) {
|
||||
if (!is_array($links)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$sanitized = [];
|
||||
$allowed_platforms = ['facebook', 'twitter', 'instagram', 'linkedin', 'youtube', 'website'];
|
||||
|
||||
foreach ($links as $link) {
|
||||
if (!is_array($link) || !isset($link['platform']) || !isset($link['url'])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$platform = sanitize_text_field($link['platform']);
|
||||
$url = esc_url_raw($link['url']);
|
||||
|
||||
if (in_array($platform, $allowed_platforms) && !empty($url)) {
|
||||
$sanitized[] = [
|
||||
'platform' => $platform,
|
||||
'url' => $url,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $sanitized;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -273,12 +273,29 @@ class EmailRenderer {
|
||||
$type = $attributes['type'] ?? 'default';
|
||||
$bg = $attributes['bg'] ?? null;
|
||||
|
||||
// Get email customization settings for colors
|
||||
$email_settings = get_option('woonoow_email_settings', []);
|
||||
$hero_gradient_start = $email_settings['hero_gradient_start'] ?? '#667eea';
|
||||
$hero_gradient_end = $email_settings['hero_gradient_end'] ?? '#764ba2';
|
||||
$hero_text_color = $email_settings['hero_text_color'] ?? '#ffffff';
|
||||
|
||||
$class = 'card';
|
||||
$style = 'width: 100%; background-color: #ffffff; border-radius: 8px;';
|
||||
$content_style = 'padding: 32px 40px;';
|
||||
|
||||
// Add type class
|
||||
// Add type class and styling
|
||||
if ($type !== 'default') {
|
||||
$class .= ' card-' . esc_attr($type);
|
||||
|
||||
// Apply gradient and text color for hero/success cards
|
||||
if ($type === 'hero' || $type === 'success') {
|
||||
$style .= sprintf(
|
||||
' background: linear-gradient(135deg, %s 0%%, %s 100%%);',
|
||||
esc_attr($hero_gradient_start),
|
||||
esc_attr($hero_gradient_end)
|
||||
);
|
||||
$content_style .= sprintf(' color: %s;', esc_attr($hero_text_color));
|
||||
}
|
||||
}
|
||||
|
||||
// Add background image
|
||||
@@ -290,13 +307,14 @@ class EmailRenderer {
|
||||
return sprintf(
|
||||
'<table role="presentation" class="%s" border="0" cellpadding="0" cellspacing="0" style="%s">
|
||||
<tr>
|
||||
<td class="content" style="padding: 32px 40px;">
|
||||
<td class="content" style="%s">
|
||||
%s
|
||||
</td>
|
||||
</tr>
|
||||
</table>',
|
||||
$class,
|
||||
$style,
|
||||
$content_style,
|
||||
$content
|
||||
);
|
||||
}
|
||||
@@ -366,23 +384,21 @@ class EmailRenderer {
|
||||
$html = file_get_contents($template_path);
|
||||
|
||||
// Get email customization settings
|
||||
$settings = get_option('woonoow_notification_settings', []);
|
||||
$email_settings = $settings['email_appearance'] ?? [];
|
||||
$email_settings = get_option('woonoow_email_settings', []);
|
||||
|
||||
// Email body background
|
||||
$body_bg = $email_settings['body_bg'] ?? '#f8f8f8';
|
||||
$body_bg = '#f8f8f8';
|
||||
|
||||
// Email header (logo or text)
|
||||
$header_type = $email_settings['header_type'] ?? 'text';
|
||||
if ($header_type === 'logo' && !empty($email_settings['header_logo'])) {
|
||||
if (!empty($email_settings['logo_url'])) {
|
||||
$header = sprintf(
|
||||
'<a href="%s"><img src="%s" alt="%s" style="max-width: 140px;"></a>',
|
||||
'<a href="%s"><img src="%s" alt="%s" style="max-width: 200px; max-height: 60px;"></a>',
|
||||
esc_url($variables['store_url']),
|
||||
esc_url($email_settings['header_logo']),
|
||||
esc_url($email_settings['logo_url']),
|
||||
esc_attr($variables['store_name'])
|
||||
);
|
||||
} else {
|
||||
$header_text = $email_settings['header_text'] ?? $variables['store_name'];
|
||||
$header_text = !empty($email_settings['header_text']) ? $email_settings['header_text'] : $variables['store_name'];
|
||||
$header = sprintf(
|
||||
'<a href="%s" style="font-size: 24px; font-weight: 700; color: #333; text-decoration: none;">%s</a>',
|
||||
esc_url($variables['store_url']),
|
||||
@@ -390,24 +406,27 @@ class EmailRenderer {
|
||||
);
|
||||
}
|
||||
|
||||
// Email footer
|
||||
$footer_text = $email_settings['footer_text'] ?? sprintf(
|
||||
// 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
|
||||
$social_html = '';
|
||||
if (!empty($email_settings['social_links'])) {
|
||||
$social_html = '<div class="social-icons" style="margin-top: 16px;">';
|
||||
foreach ($email_settings['social_links'] as $platform => $url) {
|
||||
if (!empty($url)) {
|
||||
if (!empty($email_settings['social_links']) && is_array($email_settings['social_links'])) {
|
||||
$social_html = '<div class="social-icons" style="margin-top: 16px; text-align: center;">';
|
||||
foreach ($email_settings['social_links'] as $link) {
|
||||
if (!empty($link['url']) && !empty($link['platform'])) {
|
||||
$social_html .= sprintf(
|
||||
'<a href="%s" style="display: inline-block; margin: 0 8px;"><img src="%s" alt="%s" style="width: 24px; height: 24px;"></a>',
|
||||
esc_url($url),
|
||||
$this->get_social_icon_url($platform),
|
||||
esc_attr(ucfirst($platform))
|
||||
esc_url($link['url']),
|
||||
$this->get_social_icon_url($link['platform']),
|
||||
esc_attr(ucfirst($link['platform']))
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -415,7 +434,7 @@ class EmailRenderer {
|
||||
}
|
||||
|
||||
$footer = sprintf(
|
||||
'<p style="font-family: \'Inter\', Arial, sans-serif; font-size: 13px; line-height: 1.5; color: #888888; margin: 0 0 8px 0;">%s</p>%s',
|
||||
'<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
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user