feat: complete Newsletter Campaigns Phase 1
- Add default campaign email template to DefaultTemplates.php - Add toggle settings (campaign_scheduling, subscriber_limit_enabled) - Add public unsubscribe endpoint with secure token verification - Update CampaignManager to use NewsletterController unsubscribe URLs - Add generate_unsubscribe_url() helper for email templates
This commit is contained in:
@@ -56,6 +56,23 @@ class NewsletterController {
|
||||
return current_user_can('manage_options');
|
||||
},
|
||||
]);
|
||||
|
||||
// Public unsubscribe endpoint (no auth needed, uses token)
|
||||
register_rest_route(self::API_NAMESPACE, '/newsletter/unsubscribe', [
|
||||
'methods' => 'GET',
|
||||
'callback' => [__CLASS__, 'unsubscribe'],
|
||||
'permission_callback' => '__return_true',
|
||||
'args' => [
|
||||
'email' => [
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
],
|
||||
'token' => [
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public static function get_template(WP_REST_Request $request) {
|
||||
@@ -197,4 +214,78 @@ class NewsletterController {
|
||||
],
|
||||
], 200);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle unsubscribe request
|
||||
*/
|
||||
public static function unsubscribe(WP_REST_Request $request) {
|
||||
$email = sanitize_email(urldecode($request->get_param('email')));
|
||||
$token = sanitize_text_field($request->get_param('token'));
|
||||
|
||||
// Verify token
|
||||
$expected_token = self::generate_unsubscribe_token($email);
|
||||
if (!hash_equals($expected_token, $token)) {
|
||||
return new WP_REST_Response([
|
||||
'success' => false,
|
||||
'message' => __('Invalid unsubscribe link', 'woonoow'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
// Get subscribers
|
||||
$subscribers = get_option('woonoow_newsletter_subscribers', []);
|
||||
$found = false;
|
||||
|
||||
foreach ($subscribers as &$sub) {
|
||||
if (isset($sub['email']) && $sub['email'] === $email) {
|
||||
$sub['status'] = 'unsubscribed';
|
||||
$sub['unsubscribed_at'] = current_time('mysql');
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!$found) {
|
||||
return new WP_REST_Response([
|
||||
'success' => false,
|
||||
'message' => __('Email not found', 'woonoow'),
|
||||
], 404);
|
||||
}
|
||||
|
||||
update_option('woonoow_newsletter_subscribers', $subscribers);
|
||||
|
||||
do_action('woonoow_newsletter_unsubscribed', $email);
|
||||
|
||||
// Return HTML page for nice UX
|
||||
$site_name = get_bloginfo('name');
|
||||
$html = sprintf(
|
||||
'<!DOCTYPE html><html><head><title>%s</title><style>body{font-family:system-ui,sans-serif;display:flex;justify-content:center;align-items:center;min-height:100vh;margin:0;background:#f5f5f5;}.box{background:white;padding:40px;border-radius:8px;text-align:center;box-shadow:0 2px 10px rgba(0,0,0,0.1);max-width:400px;}h1{color:#333;margin-bottom:16px;}p{color:#666;}</style></head><body><div class="box"><h1>✓ Unsubscribed</h1><p>You have been unsubscribed from %s newsletter.</p></div></body></html>',
|
||||
__('Unsubscribed', 'woonoow'),
|
||||
esc_html($site_name)
|
||||
);
|
||||
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
echo $html;
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate secure unsubscribe token
|
||||
*/
|
||||
private static function generate_unsubscribe_token($email) {
|
||||
$secret = wp_salt('auth');
|
||||
return hash_hmac('sha256', $email, $secret);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate unsubscribe URL for email templates
|
||||
*/
|
||||
public static function generate_unsubscribe_url($email) {
|
||||
$token = self::generate_unsubscribe_token($email);
|
||||
$base_url = rest_url('woonoow/v1/newsletter/unsubscribe');
|
||||
return add_query_arg([
|
||||
'email' => urlencode($email),
|
||||
'token' => $token,
|
||||
], $base_url);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user