fix: resolve container width issues, spa redirects, and appearance settings overwrite. feat: enhance order/sub details and newsletter layout
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Campaigns REST Controller
|
||||
*
|
||||
@@ -13,64 +14,67 @@ use WP_REST_Request;
|
||||
use WP_REST_Response;
|
||||
use WP_Error;
|
||||
use WooNooW\Core\Campaigns\CampaignManager;
|
||||
use WooNooW\Core\ActivityLog\Logger;
|
||||
|
||||
class CampaignsController
|
||||
{
|
||||
|
||||
class CampaignsController {
|
||||
|
||||
const API_NAMESPACE = 'woonoow/v1';
|
||||
|
||||
|
||||
/**
|
||||
* Register REST routes
|
||||
*/
|
||||
public static function register_routes() {
|
||||
public static function register_routes()
|
||||
{
|
||||
// List campaigns
|
||||
register_rest_route(self::API_NAMESPACE, '/campaigns', [
|
||||
'methods' => 'GET',
|
||||
'callback' => [__CLASS__, 'get_campaigns'],
|
||||
'permission_callback' => [__CLASS__, 'check_admin_permission'],
|
||||
]);
|
||||
|
||||
|
||||
// Create campaign
|
||||
register_rest_route(self::API_NAMESPACE, '/campaigns', [
|
||||
'methods' => 'POST',
|
||||
'callback' => [__CLASS__, 'create_campaign'],
|
||||
'permission_callback' => [__CLASS__, 'check_admin_permission'],
|
||||
]);
|
||||
|
||||
|
||||
// Get single campaign
|
||||
register_rest_route(self::API_NAMESPACE, '/campaigns/(?P<id>\d+)', [
|
||||
'methods' => 'GET',
|
||||
'callback' => [__CLASS__, 'get_campaign'],
|
||||
'permission_callback' => [__CLASS__, 'check_admin_permission'],
|
||||
]);
|
||||
|
||||
|
||||
// Update campaign
|
||||
register_rest_route(self::API_NAMESPACE, '/campaigns/(?P<id>\d+)', [
|
||||
'methods' => 'PUT',
|
||||
'callback' => [__CLASS__, 'update_campaign'],
|
||||
'permission_callback' => [__CLASS__, 'check_admin_permission'],
|
||||
]);
|
||||
|
||||
|
||||
// Delete campaign
|
||||
register_rest_route(self::API_NAMESPACE, '/campaigns/(?P<id>\d+)', [
|
||||
'methods' => 'DELETE',
|
||||
'callback' => [__CLASS__, 'delete_campaign'],
|
||||
'permission_callback' => [__CLASS__, 'check_admin_permission'],
|
||||
]);
|
||||
|
||||
|
||||
// Send campaign
|
||||
register_rest_route(self::API_NAMESPACE, '/campaigns/(?P<id>\d+)/send', [
|
||||
'methods' => 'POST',
|
||||
'callback' => [__CLASS__, 'send_campaign'],
|
||||
'permission_callback' => [__CLASS__, 'check_admin_permission'],
|
||||
]);
|
||||
|
||||
|
||||
// Send test email
|
||||
register_rest_route(self::API_NAMESPACE, '/campaigns/(?P<id>\d+)/test', [
|
||||
'methods' => 'POST',
|
||||
'callback' => [__CLASS__, 'send_test_email'],
|
||||
'permission_callback' => [__CLASS__, 'check_admin_permission'],
|
||||
]);
|
||||
|
||||
|
||||
// Preview campaign
|
||||
register_rest_route(self::API_NAMESPACE, '/campaigns/(?P<id>\d+)/preview', [
|
||||
'methods' => 'GET',
|
||||
@@ -78,30 +82,33 @@ class CampaignsController {
|
||||
'permission_callback' => [__CLASS__, 'check_admin_permission'],
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check admin permission
|
||||
*/
|
||||
public static function check_admin_permission() {
|
||||
public static function check_admin_permission()
|
||||
{
|
||||
return current_user_can('manage_options');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get all campaigns
|
||||
*/
|
||||
public static function get_campaigns(WP_REST_Request $request) {
|
||||
public static function get_campaigns(WP_REST_Request $request)
|
||||
{
|
||||
$campaigns = CampaignManager::get_all();
|
||||
|
||||
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'data' => $campaigns,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create campaign
|
||||
*/
|
||||
public static function create_campaign(WP_REST_Request $request) {
|
||||
public static function create_campaign(WP_REST_Request $request)
|
||||
{
|
||||
$data = [
|
||||
'title' => $request->get_param('title'),
|
||||
'subject' => $request->get_param('subject'),
|
||||
@@ -109,52 +116,54 @@ class CampaignsController {
|
||||
'status' => $request->get_param('status') ?: 'draft',
|
||||
'scheduled_at' => $request->get_param('scheduled_at'),
|
||||
];
|
||||
|
||||
|
||||
$campaign_id = CampaignManager::create($data);
|
||||
|
||||
|
||||
if (is_wp_error($campaign_id)) {
|
||||
return new WP_REST_Response([
|
||||
'success' => false,
|
||||
'error' => $campaign_id->get_error_message(),
|
||||
], 400);
|
||||
}
|
||||
|
||||
|
||||
$campaign = CampaignManager::get($campaign_id);
|
||||
|
||||
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'data' => $campaign,
|
||||
], 201);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get single campaign
|
||||
*/
|
||||
public static function get_campaign(WP_REST_Request $request) {
|
||||
public static function get_campaign(WP_REST_Request $request)
|
||||
{
|
||||
$campaign_id = (int) $request->get_param('id');
|
||||
$campaign = CampaignManager::get($campaign_id);
|
||||
|
||||
|
||||
if (!$campaign) {
|
||||
return new WP_REST_Response([
|
||||
'success' => false,
|
||||
'error' => __('Campaign not found', 'woonoow'),
|
||||
], 404);
|
||||
}
|
||||
|
||||
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'data' => $campaign,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Update campaign
|
||||
*/
|
||||
public static function update_campaign(WP_REST_Request $request) {
|
||||
public static function update_campaign(WP_REST_Request $request)
|
||||
{
|
||||
$campaign_id = (int) $request->get_param('id');
|
||||
|
||||
|
||||
$data = [];
|
||||
|
||||
|
||||
if ($request->has_param('title')) {
|
||||
$data['title'] = $request->get_param('title');
|
||||
}
|
||||
@@ -170,60 +179,62 @@ class CampaignsController {
|
||||
if ($request->has_param('scheduled_at')) {
|
||||
$data['scheduled_at'] = $request->get_param('scheduled_at');
|
||||
}
|
||||
|
||||
|
||||
$result = CampaignManager::update($campaign_id, $data);
|
||||
|
||||
|
||||
if (is_wp_error($result)) {
|
||||
return new WP_REST_Response([
|
||||
'success' => false,
|
||||
'error' => $result->get_error_message(),
|
||||
], 400);
|
||||
}
|
||||
|
||||
|
||||
$campaign = CampaignManager::get($campaign_id);
|
||||
|
||||
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'data' => $campaign,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delete campaign
|
||||
*/
|
||||
public static function delete_campaign(WP_REST_Request $request) {
|
||||
public static function delete_campaign(WP_REST_Request $request)
|
||||
{
|
||||
$campaign_id = (int) $request->get_param('id');
|
||||
|
||||
|
||||
$result = CampaignManager::delete($campaign_id);
|
||||
|
||||
|
||||
if (!$result) {
|
||||
return new WP_REST_Response([
|
||||
'success' => false,
|
||||
'error' => __('Failed to delete campaign', 'woonoow'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'message' => __('Campaign deleted', 'woonoow'),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send campaign
|
||||
*/
|
||||
public static function send_campaign(WP_REST_Request $request) {
|
||||
public static function send_campaign(WP_REST_Request $request)
|
||||
{
|
||||
$campaign_id = (int) $request->get_param('id');
|
||||
|
||||
|
||||
$result = CampaignManager::send($campaign_id);
|
||||
|
||||
|
||||
if (!$result['success']) {
|
||||
return new WP_REST_Response([
|
||||
'success' => false,
|
||||
'error' => $result['error'],
|
||||
], 400);
|
||||
}
|
||||
|
||||
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'message' => sprintf(
|
||||
@@ -236,63 +247,80 @@ class CampaignsController {
|
||||
'total' => $result['total'],
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send test email
|
||||
*/
|
||||
public static function send_test_email(WP_REST_Request $request) {
|
||||
public static function send_test_email(WP_REST_Request $request)
|
||||
{
|
||||
$campaign_id = (int) $request->get_param('id');
|
||||
$email = sanitize_email($request->get_param('email'));
|
||||
|
||||
|
||||
if (!is_email($email)) {
|
||||
return new WP_REST_Response([
|
||||
'success' => false,
|
||||
'error' => __('Invalid email address', 'woonoow'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
|
||||
$result = CampaignManager::send_test($campaign_id, $email);
|
||||
|
||||
|
||||
if (!$result) {
|
||||
return new WP_REST_Response([
|
||||
'success' => false,
|
||||
'error' => __('Failed to send test email', 'woonoow'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
|
||||
// Log to activity log
|
||||
Logger::log(
|
||||
'test_sent',
|
||||
'campaign',
|
||||
$campaign_id,
|
||||
sprintf(__('Test email sent to %s', 'woonoow'), $email)
|
||||
);
|
||||
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'message' => sprintf(__('Test email sent to %s', 'woonoow'), $email),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Preview campaign
|
||||
*/
|
||||
public static function preview_campaign(WP_REST_Request $request) {
|
||||
public static function preview_campaign(WP_REST_Request $request)
|
||||
{
|
||||
$campaign_id = (int) $request->get_param('id');
|
||||
$campaign = CampaignManager::get($campaign_id);
|
||||
|
||||
|
||||
if (!$campaign) {
|
||||
return new WP_REST_Response([
|
||||
'success' => false,
|
||||
'error' => __('Campaign not found', 'woonoow'),
|
||||
], 404);
|
||||
}
|
||||
|
||||
|
||||
// Use reflection to call private render method or make it public
|
||||
// For now, return a simple preview
|
||||
$renderer = \WooNooW\Core\Notifications\EmailRenderer::instance();
|
||||
$template = $renderer->get_template_settings('newsletter_campaign', 'customer');
|
||||
|
||||
|
||||
$content = $campaign['content'];
|
||||
$subject = $campaign['subject'] ?: $campaign['title'];
|
||||
|
||||
|
||||
if ($template) {
|
||||
// Use template subject if available
|
||||
if (!empty($template['subject'])) {
|
||||
$subject = $template['subject'];
|
||||
}
|
||||
$content = str_replace('{content}', $campaign['content'], $template['body']);
|
||||
$content = str_replace('{campaign_title}', $campaign['title'], $content);
|
||||
}
|
||||
|
||||
|
||||
// Replace campaign_title in subject
|
||||
$subject = str_replace('{campaign_title}', $campaign['title'], $subject);
|
||||
|
||||
// Replace placeholders
|
||||
$site_name = get_bloginfo('name');
|
||||
$content = str_replace(['{site_name}', '{store_name}'], $site_name, $content);
|
||||
@@ -301,7 +329,10 @@ class CampaignsController {
|
||||
$content = str_replace('{unsubscribe_url}', '#unsubscribe', $content);
|
||||
$content = str_replace('{current_date}', date_i18n(get_option('date_format')), $content);
|
||||
$content = str_replace('{current_year}', date('Y'), $content);
|
||||
|
||||
|
||||
// Parse card shortcodes before rendering
|
||||
$content = $renderer->parse_cards($content);
|
||||
|
||||
// Render with design template
|
||||
$design_path = $renderer->get_design_template();
|
||||
if (file_exists($design_path)) {
|
||||
@@ -310,7 +341,7 @@ class CampaignsController {
|
||||
'site_url' => home_url(),
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'subject' => $subject,
|
||||
|
||||
@@ -311,12 +311,27 @@ class CheckoutController
|
||||
return ['error' => __('No items provided', 'woonoow')];
|
||||
}
|
||||
|
||||
// Security: Rate limiting check
|
||||
if (\WooNooW\Compat\SecuritySettingsProvider::is_rate_limited()) {
|
||||
return ['error' => __('Too many orders. Please try again later.', 'woonoow')];
|
||||
}
|
||||
|
||||
// Security: CAPTCHA validation
|
||||
$captcha_token = $payload['captcha_token'] ?? '';
|
||||
$captcha_result = \WooNooW\Compat\SecuritySettingsProvider::validate_captcha($captcha_token);
|
||||
if (is_wp_error($captcha_result)) {
|
||||
return ['error' => $captcha_result->get_error_message()];
|
||||
}
|
||||
|
||||
// Create order
|
||||
$order = wc_create_order();
|
||||
if (is_wp_error($order)) {
|
||||
return ['error' => $order->get_error_message()];
|
||||
}
|
||||
|
||||
// Track if user was logged in during this request (for frontend page reload)
|
||||
$user_logged_in = false;
|
||||
|
||||
// Set customer ID if user is logged in
|
||||
if (is_user_logged_in()) {
|
||||
$user_id = get_current_user_id();
|
||||
@@ -358,8 +373,9 @@ class CheckoutController
|
||||
$existing_user = get_user_by('email', $email);
|
||||
|
||||
if ($existing_user) {
|
||||
// User exists - link order to them
|
||||
// User exists - link order to them (but do NOT auto-login for security)
|
||||
$order->set_customer_id($existing_user->ID);
|
||||
// Note: user_logged_in stays false - existing users must authenticate separately
|
||||
} else {
|
||||
// Create new user account
|
||||
$password = wp_generate_password(12, true, true);
|
||||
@@ -387,6 +403,7 @@ class CheckoutController
|
||||
// AUTO-LOGIN: Set authentication cookie so user is logged in after page reload
|
||||
wp_set_auth_cookie($new_user_id, true);
|
||||
wp_set_current_user($new_user_id);
|
||||
$user_logged_in = true;
|
||||
|
||||
// Set WooCommerce customer billing data
|
||||
$customer = new \WC_Customer($new_user_id);
|
||||
@@ -509,6 +526,9 @@ class CheckoutController
|
||||
WC()->cart->empty_cart();
|
||||
}
|
||||
|
||||
// Record this order attempt for rate limiting
|
||||
\WooNooW\Compat\SecuritySettingsProvider::record_order_attempt();
|
||||
|
||||
return [
|
||||
'ok' => true,
|
||||
'order_id' => $order->get_id(),
|
||||
@@ -516,6 +536,7 @@ class CheckoutController
|
||||
'status' => $order->get_status(),
|
||||
'pay_url' => $order->get_checkout_payment_url(),
|
||||
'thankyou_url' => $order->get_checkout_order_received_url(),
|
||||
'user_logged_in' => $user_logged_in, // True if user was logged in during this request (requires page reload)
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,19 @@
|
||||
<?php
|
||||
|
||||
namespace WooNooW\API;
|
||||
|
||||
use WP_REST_Request;
|
||||
use WP_REST_Response;
|
||||
use WP_Error;
|
||||
use WooNooW\Core\Validation;
|
||||
use WooNooW\Database\SubscriberTable;
|
||||
|
||||
class NewsletterController {
|
||||
class NewsletterController
|
||||
{
|
||||
const API_NAMESPACE = 'woonoow/v1';
|
||||
|
||||
public static function register_routes() {
|
||||
|
||||
public static function register_routes()
|
||||
{
|
||||
register_rest_route(self::API_NAMESPACE, '/newsletter/subscribe', [
|
||||
'methods' => 'POST',
|
||||
'callback' => [__CLASS__, 'subscribe'],
|
||||
@@ -18,45 +22,45 @@ class NewsletterController {
|
||||
'email' => [
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
'validate_callback' => function($param) {
|
||||
'validate_callback' => function ($param) {
|
||||
return is_email($param);
|
||||
},
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
|
||||
register_rest_route(self::API_NAMESPACE, '/newsletter/subscribers', [
|
||||
'methods' => 'GET',
|
||||
'callback' => [__CLASS__, 'get_subscribers'],
|
||||
'permission_callback' => function() {
|
||||
'permission_callback' => function () {
|
||||
return current_user_can('manage_options');
|
||||
},
|
||||
]);
|
||||
|
||||
|
||||
register_rest_route(self::API_NAMESPACE, '/newsletter/subscribers/(?P<email>[^/]+)', [
|
||||
'methods' => 'DELETE',
|
||||
'callback' => [__CLASS__, 'delete_subscriber'],
|
||||
'permission_callback' => function() {
|
||||
'permission_callback' => function () {
|
||||
return current_user_can('manage_options');
|
||||
},
|
||||
]);
|
||||
|
||||
|
||||
register_rest_route(self::API_NAMESPACE, '/newsletter/template/(?P<template>[^/]+)', [
|
||||
'methods' => 'GET',
|
||||
'callback' => [__CLASS__, 'get_template'],
|
||||
'permission_callback' => function() {
|
||||
'permission_callback' => function () {
|
||||
return current_user_can('manage_options');
|
||||
},
|
||||
]);
|
||||
|
||||
|
||||
register_rest_route(self::API_NAMESPACE, '/newsletter/template/(?P<template>[^/]+)', [
|
||||
'methods' => 'POST',
|
||||
'callback' => [__CLASS__, 'save_template'],
|
||||
'permission_callback' => function() {
|
||||
'permission_callback' => function () {
|
||||
return current_user_can('manage_options');
|
||||
},
|
||||
]);
|
||||
|
||||
|
||||
// Public unsubscribe endpoint (no auth needed, uses token)
|
||||
register_rest_route(self::API_NAMESPACE, '/newsletter/unsubscribe', [
|
||||
'methods' => 'GET',
|
||||
@@ -73,139 +77,381 @@ class NewsletterController {
|
||||
],
|
||||
],
|
||||
]);
|
||||
|
||||
// Public confirm endpoint (double opt-in)
|
||||
register_rest_route(self::API_NAMESPACE, '/newsletter/confirm', [
|
||||
'methods' => 'GET',
|
||||
'callback' => [__CLASS__, 'confirm'],
|
||||
'permission_callback' => '__return_true',
|
||||
'args' => [
|
||||
'email' => [
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
],
|
||||
'token' => [
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
public static function get_template(WP_REST_Request $request) {
|
||||
|
||||
public static function get_template(WP_REST_Request $request)
|
||||
{
|
||||
$template = $request->get_param('template');
|
||||
$option_key = "woonoow_newsletter_{$template}_template";
|
||||
|
||||
|
||||
$data = get_option($option_key, [
|
||||
'subject' => $template === 'welcome' ? 'Welcome to {site_name} Newsletter!' : 'Confirm your newsletter subscription',
|
||||
'content' => $template === 'welcome'
|
||||
'content' => $template === 'welcome'
|
||||
? "Thank you for subscribing to our newsletter!\n\nYou'll receive updates about our latest products and offers.\n\nBest regards,\n{site_name}"
|
||||
: "Please confirm your newsletter subscription by clicking the link below:\n\n{confirmation_url}\n\nBest regards,\n{site_name}",
|
||||
]);
|
||||
|
||||
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'subject' => $data['subject'] ?? '',
|
||||
'content' => $data['content'] ?? '',
|
||||
], 200);
|
||||
}
|
||||
|
||||
public static function save_template(WP_REST_Request $request) {
|
||||
|
||||
public static function save_template(WP_REST_Request $request)
|
||||
{
|
||||
$template = $request->get_param('template');
|
||||
$subject = sanitize_text_field($request->get_param('subject'));
|
||||
$content = wp_kses_post($request->get_param('content'));
|
||||
|
||||
|
||||
$option_key = "woonoow_newsletter_{$template}_template";
|
||||
|
||||
|
||||
update_option($option_key, [
|
||||
'subject' => $subject,
|
||||
'content' => $content,
|
||||
]);
|
||||
|
||||
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'message' => 'Template saved successfully',
|
||||
], 200);
|
||||
}
|
||||
|
||||
public static function delete_subscriber(WP_REST_Request $request) {
|
||||
$email = urldecode($request->get_param('email'));
|
||||
|
||||
public static function delete_subscriber(WP_REST_Request $request)
|
||||
{
|
||||
$email = sanitize_email(urldecode($request->get_param('email')));
|
||||
|
||||
if (self::use_custom_table()) {
|
||||
$result = SubscriberTable::delete_by_email($email);
|
||||
if ($result) {
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'message' => 'Subscriber removed successfully',
|
||||
], 200);
|
||||
}
|
||||
return new WP_Error('not_found', 'Subscriber not found', ['status' => 404]);
|
||||
}
|
||||
|
||||
// Legacy: wp_options storage
|
||||
$subscribers = get_option('woonoow_newsletter_subscribers', []);
|
||||
|
||||
$subscribers = array_filter($subscribers, function($sub) use ($email) {
|
||||
|
||||
$subscribers = array_filter($subscribers, function ($sub) use ($email) {
|
||||
return isset($sub['email']) && $sub['email'] !== $email;
|
||||
});
|
||||
|
||||
|
||||
update_option('woonoow_newsletter_subscribers', array_values($subscribers));
|
||||
|
||||
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'message' => 'Subscriber removed successfully',
|
||||
], 200);
|
||||
}
|
||||
|
||||
public static function subscribe(WP_REST_Request $request) {
|
||||
|
||||
/**
|
||||
* Check if custom subscriber table should be used
|
||||
*/
|
||||
private static function use_custom_table()
|
||||
{
|
||||
return SubscriberTable::table_exists();
|
||||
}
|
||||
|
||||
public static function subscribe(WP_REST_Request $request)
|
||||
{
|
||||
$email = sanitize_email($request->get_param('email'));
|
||||
|
||||
$consent = (bool) $request->get_param('consent');
|
||||
|
||||
// Rate limiting (5 requests per IP per hour)
|
||||
$ip = $_SERVER['REMOTE_ADDR'] ?? '';
|
||||
$rate_key = 'woonoow_newsletter_rate_' . md5($ip);
|
||||
$attempts = (int) get_transient($rate_key);
|
||||
|
||||
if ($attempts >= 5) {
|
||||
return new WP_Error('rate_limited', __('Too many requests. Please try again later.', 'woonoow'), ['status' => 429]);
|
||||
}
|
||||
set_transient($rate_key, $attempts + 1, HOUR_IN_SECONDS);
|
||||
|
||||
// Use centralized validation with extensible filter hooks
|
||||
$validation = Validation::validate_email($email, 'newsletter_subscribe');
|
||||
|
||||
|
||||
if (is_wp_error($validation)) {
|
||||
return $validation;
|
||||
}
|
||||
|
||||
// Get existing subscribers (now stored as objects with metadata)
|
||||
$subscribers = get_option('woonoow_newsletter_subscribers', []);
|
||||
|
||||
// Check if already subscribed
|
||||
$existing = array_filter($subscribers, function($sub) use ($email) {
|
||||
return isset($sub['email']) && $sub['email'] === $email;
|
||||
});
|
||||
|
||||
if (!empty($existing)) {
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'message' => 'You are already subscribed to our newsletter!',
|
||||
], 200);
|
||||
|
||||
// Check GDPR consent requirement
|
||||
$gdpr_required = get_option('woonoow_newsletter_gdpr_consent', false);
|
||||
if ($gdpr_required && !$consent) {
|
||||
return new WP_Error('consent_required', __('Please accept the terms to subscribe.', 'woonoow'), ['status' => 400]);
|
||||
}
|
||||
|
||||
|
||||
// Check if email belongs to a WP user
|
||||
$user = get_user_by('email', $email);
|
||||
$user_id = $user ? $user->ID : null;
|
||||
|
||||
// Add new subscriber with metadata
|
||||
$subscribers[] = [
|
||||
'email' => $email,
|
||||
'user_id' => $user_id,
|
||||
'status' => 'active',
|
||||
'subscribed_at' => current_time('mysql'),
|
||||
'ip_address' => $_SERVER['REMOTE_ADDR'] ?? '',
|
||||
];
|
||||
|
||||
update_option('woonoow_newsletter_subscribers', $subscribers);
|
||||
|
||||
// Trigger notification events
|
||||
|
||||
// Check double opt-in setting
|
||||
$double_opt_in = get_option('woonoow_newsletter_double_opt_in', true);
|
||||
$status = $double_opt_in ? 'pending' : 'active';
|
||||
|
||||
if (self::use_custom_table()) {
|
||||
// Use custom table
|
||||
$existing = SubscriberTable::get_by_email($email);
|
||||
|
||||
if ($existing) {
|
||||
if ($existing['status'] === 'active') {
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'message' => __('You are already subscribed to our newsletter!', 'woonoow'),
|
||||
], 200);
|
||||
}
|
||||
if ($existing['status'] === 'pending') {
|
||||
self::send_confirmation_email($email, $existing['user_id'] ?? null);
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'message' => __('Confirmation email resent. Please check your inbox.', 'woonoow'),
|
||||
], 200);
|
||||
}
|
||||
// Resubscribe (was unsubscribed)
|
||||
SubscriberTable::update_by_email($email, [
|
||||
'status' => $status,
|
||||
'consent' => $consent ? 1 : 0,
|
||||
'subscribed_at' => current_time('mysql'),
|
||||
'ip_address' => $ip,
|
||||
]);
|
||||
} else {
|
||||
// New subscriber
|
||||
SubscriberTable::add([
|
||||
'email' => $email,
|
||||
'user_id' => $user_id,
|
||||
'status' => $status,
|
||||
'consent' => $consent,
|
||||
'subscribed_at' => current_time('mysql'),
|
||||
'ip_address' => $ip,
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
// Legacy: wp_options storage
|
||||
$subscribers = get_option('woonoow_newsletter_subscribers', []);
|
||||
|
||||
// Check if already subscribed
|
||||
$existing_key = null;
|
||||
foreach ($subscribers as $key => $sub) {
|
||||
if (isset($sub['email']) && $sub['email'] === $email) {
|
||||
$existing_key = $key;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($existing_key !== null) {
|
||||
$existing = $subscribers[$existing_key];
|
||||
if (($existing['status'] ?? 'active') === 'active') {
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'message' => __('You are already subscribed to our newsletter!', 'woonoow'),
|
||||
], 200);
|
||||
}
|
||||
if (($existing['status'] ?? '') === 'pending') {
|
||||
self::send_confirmation_email($email, $existing['user_id'] ?? null);
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'message' => __('Confirmation email resent. Please check your inbox.', 'woonoow'),
|
||||
], 200);
|
||||
}
|
||||
}
|
||||
|
||||
$subscribers[] = [
|
||||
'email' => $email,
|
||||
'user_id' => $user_id,
|
||||
'status' => $status,
|
||||
'consent' => $consent,
|
||||
'subscribed_at' => current_time('mysql'),
|
||||
'ip_address' => $ip,
|
||||
];
|
||||
|
||||
update_option('woonoow_newsletter_subscribers', $subscribers);
|
||||
}
|
||||
|
||||
if ($double_opt_in) {
|
||||
// Send confirmation email
|
||||
self::send_confirmation_email($email, $user_id);
|
||||
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'message' => __('Please check your email to confirm your subscription.', 'woonoow'),
|
||||
], 200);
|
||||
}
|
||||
|
||||
// Direct subscription (no double opt-in)
|
||||
do_action('woonoow_newsletter_subscribed', $email, $user_id);
|
||||
|
||||
// Trigger notification system events (uses email builder)
|
||||
|
||||
do_action('woonoow/notification/event', 'newsletter_welcome', 'customer', [
|
||||
'email' => $email,
|
||||
'user_id' => $user_id,
|
||||
'subscribed_at' => current_time('mysql'),
|
||||
]);
|
||||
|
||||
|
||||
do_action('woonoow/notification/event', 'newsletter_subscribed_admin', 'staff', [
|
||||
'email' => $email,
|
||||
'user_id' => $user_id,
|
||||
'subscribed_at' => current_time('mysql'),
|
||||
]);
|
||||
|
||||
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'message' => 'Successfully subscribed! Check your email for confirmation.',
|
||||
'message' => __('Successfully subscribed to our newsletter!', 'woonoow'),
|
||||
], 200);
|
||||
}
|
||||
|
||||
private static function send_welcome_email($email) {
|
||||
$site_name = get_bloginfo('name');
|
||||
$template = get_option('woonoow_newsletter_welcome_template', '');
|
||||
|
||||
if (empty($template)) {
|
||||
$template = "Thank you for subscribing to our newsletter!\n\nYou'll receive updates about our latest products and offers.\n\nBest regards,\n{site_name}";
|
||||
}
|
||||
|
||||
$subject = sprintf('Welcome to %s Newsletter!', $site_name);
|
||||
$message = str_replace('{site_name}', $site_name, $template);
|
||||
|
||||
wp_mail($email, $subject, $message);
|
||||
|
||||
/**
|
||||
* Send confirmation email for double opt-in
|
||||
*/
|
||||
private static function send_confirmation_email($email, $user_id = null)
|
||||
{
|
||||
$confirmation_url = self::generate_confirmation_url($email);
|
||||
|
||||
do_action('woonoow/notification/event', 'newsletter_confirm', 'customer', [
|
||||
'email' => $email,
|
||||
'user_id' => $user_id,
|
||||
'confirmation_url' => $confirmation_url,
|
||||
]);
|
||||
}
|
||||
|
||||
public static function get_subscribers(WP_REST_Request $request) {
|
||||
|
||||
/**
|
||||
* Generate confirmation URL with secure token
|
||||
*/
|
||||
public static function generate_confirmation_url($email)
|
||||
{
|
||||
$token = self::generate_unsubscribe_token($email); // Reuse same token logic
|
||||
$base_url = rest_url('woonoow/v1/newsletter/confirm');
|
||||
return add_query_arg([
|
||||
'email' => urlencode($email),
|
||||
'token' => $token,
|
||||
], $base_url);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle confirmation request (double opt-in)
|
||||
*/
|
||||
public static function confirm(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 confirmation link', 'woonoow'),
|
||||
], 400);
|
||||
}
|
||||
|
||||
$found = false;
|
||||
$user_id = null;
|
||||
|
||||
if (self::use_custom_table()) {
|
||||
$existing = SubscriberTable::get_by_email($email);
|
||||
if ($existing) {
|
||||
if ($existing['status'] === 'active') {
|
||||
$found = true;
|
||||
} else {
|
||||
SubscriberTable::update_by_email($email, [
|
||||
'status' => 'active',
|
||||
'confirmed_at' => current_time('mysql'),
|
||||
]);
|
||||
$user_id = $existing['user_id'] ?? null;
|
||||
$found = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Legacy: wp_options
|
||||
$subscribers = get_option('woonoow_newsletter_subscribers', []);
|
||||
|
||||
foreach ($subscribers as &$sub) {
|
||||
if (isset($sub['email']) && $sub['email'] === $email) {
|
||||
if (($sub['status'] ?? '') === 'active') {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
$sub['status'] = 'active';
|
||||
$sub['confirmed_at'] = current_time('mysql');
|
||||
$user_id = $sub['user_id'] ?? null;
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($found) {
|
||||
update_option('woonoow_newsletter_subscribers', $subscribers);
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger subscription events
|
||||
do_action('woonoow_newsletter_subscribed', $email, $user_id);
|
||||
|
||||
do_action('woonoow/notification/event', 'newsletter_welcome', 'customer', [
|
||||
'email' => $email,
|
||||
'user_id' => $user_id,
|
||||
'subscribed_at' => current_time('mysql'),
|
||||
]);
|
||||
|
||||
do_action('woonoow/notification/event', 'newsletter_subscribed_admin', 'staff', [
|
||||
'email' => $email,
|
||||
'user_id' => $user_id,
|
||||
'subscribed_at' => current_time('mysql'),
|
||||
]);
|
||||
|
||||
// Return HTML page for nice UX
|
||||
$site_name = get_bloginfo('name');
|
||||
$shop_url = wc_get_page_permalink('shop') ?: home_url();
|
||||
$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;}a{display:inline-block;margin-top:20px;padding:12px 24px;background:#333;color:white;text-decoration:none;border-radius:6px;}</style></head><body><div class="box"><h1>✓ Confirmed!</h1><p>You are now subscribed to %s newsletter.</p><a href="%s">Continue Shopping</a></div></body></html>',
|
||||
__('Subscription Confirmed', 'woonoow'),
|
||||
esc_html($site_name),
|
||||
esc_url($shop_url)
|
||||
);
|
||||
|
||||
header('Content-Type: text/html; charset=utf-8');
|
||||
echo $html;
|
||||
exit;
|
||||
}
|
||||
|
||||
// Dead code removed: send_welcome_email() - now handled via notification system
|
||||
|
||||
public static function get_subscribers(WP_REST_Request $request)
|
||||
{
|
||||
if (self::use_custom_table()) {
|
||||
$result = SubscriberTable::get_all([
|
||||
'per_page' => 100,
|
||||
'page' => 1,
|
||||
]);
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'data' => [
|
||||
'subscribers' => $result['items'],
|
||||
'count' => $result['total'],
|
||||
],
|
||||
], 200);
|
||||
}
|
||||
|
||||
// Legacy: wp_options
|
||||
$subscribers = get_option('woonoow_newsletter_subscribers', []);
|
||||
|
||||
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'data' => [
|
||||
@@ -214,14 +460,15 @@ class NewsletterController {
|
||||
],
|
||||
], 200);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Handle unsubscribe request
|
||||
*/
|
||||
public static function unsubscribe(WP_REST_Request $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)) {
|
||||
@@ -230,31 +477,45 @@ class NewsletterController {
|
||||
'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');
|
||||
|
||||
if (self::use_custom_table()) {
|
||||
$existing = SubscriberTable::get_by_email($email);
|
||||
if ($existing) {
|
||||
SubscriberTable::update_by_email($email, [
|
||||
'status' => 'unsubscribed',
|
||||
'unsubscribed_at' => current_time('mysql'),
|
||||
]);
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Legacy: wp_options
|
||||
$subscribers = get_option('woonoow_newsletter_subscribers', []);
|
||||
|
||||
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) {
|
||||
update_option('woonoow_newsletter_subscribers', $subscribers);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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(
|
||||
@@ -262,24 +523,26 @@ class NewsletterController {
|
||||
__('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) {
|
||||
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) {
|
||||
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([
|
||||
@@ -288,4 +551,3 @@ class NewsletterController {
|
||||
], $base_url);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -371,13 +371,13 @@ class ProductsController
|
||||
}
|
||||
|
||||
// Virtual and downloadable
|
||||
if (isset($data['virtual'])) {
|
||||
if (array_key_exists('virtual', $data)) {
|
||||
$product->set_virtual((bool) $data['virtual']);
|
||||
}
|
||||
if (isset($data['downloadable'])) {
|
||||
if (array_key_exists('downloadable', $data)) {
|
||||
$product->set_downloadable((bool) $data['downloadable']);
|
||||
}
|
||||
if (isset($data['featured'])) {
|
||||
if (array_key_exists('featured', $data)) {
|
||||
$product->set_featured((bool) $data['featured']);
|
||||
}
|
||||
|
||||
@@ -510,13 +510,13 @@ class ProductsController
|
||||
if (isset($data['height'])) $product->set_height(self::sanitize_number($data['height']));
|
||||
|
||||
// Virtual and downloadable
|
||||
if (isset($data['virtual'])) {
|
||||
if (array_key_exists('virtual', $data)) {
|
||||
$product->set_virtual((bool) $data['virtual']);
|
||||
}
|
||||
if (isset($data['downloadable'])) {
|
||||
if (array_key_exists('downloadable', $data)) {
|
||||
$product->set_downloadable((bool) $data['downloadable']);
|
||||
}
|
||||
if (isset($data['featured'])) {
|
||||
if (array_key_exists('featured', $data)) {
|
||||
$product->set_featured((bool) $data['featured']);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Store REST API Controller
|
||||
*
|
||||
@@ -11,28 +12,31 @@ namespace WooNooW\API;
|
||||
|
||||
use WooNooW\Compat\StoreSettingsProvider;
|
||||
use WooNooW\Compat\CustomerSettingsProvider;
|
||||
use WooNooW\Compat\SecuritySettingsProvider;
|
||||
use WP_REST_Controller;
|
||||
use WP_REST_Server;
|
||||
use WP_REST_Request;
|
||||
use WP_REST_Response;
|
||||
use WP_Error;
|
||||
|
||||
class StoreController extends WP_REST_Controller {
|
||||
|
||||
class StoreController extends WP_REST_Controller
|
||||
{
|
||||
|
||||
/**
|
||||
* Namespace
|
||||
*/
|
||||
protected $namespace = 'woonoow/v1';
|
||||
|
||||
|
||||
/**
|
||||
* Rest base
|
||||
*/
|
||||
protected $rest_base = 'store';
|
||||
|
||||
|
||||
/**
|
||||
* Register routes
|
||||
*/
|
||||
public function register_routes() {
|
||||
public function register_routes()
|
||||
{
|
||||
// GET /woonoow/v1/store/branding (PUBLIC - for login page)
|
||||
register_rest_route($this->namespace, '/' . $this->rest_base . '/branding', [
|
||||
[
|
||||
@@ -41,7 +45,7 @@ class StoreController extends WP_REST_Controller {
|
||||
'permission_callback' => '__return_true', // Public endpoint
|
||||
],
|
||||
]);
|
||||
|
||||
|
||||
// GET /woonoow/v1/store/settings
|
||||
register_rest_route($this->namespace, '/' . $this->rest_base . '/settings', [
|
||||
[
|
||||
@@ -50,7 +54,7 @@ class StoreController extends WP_REST_Controller {
|
||||
'permission_callback' => [$this, 'check_permission'],
|
||||
],
|
||||
]);
|
||||
|
||||
|
||||
// POST /woonoow/v1/store/settings
|
||||
register_rest_route($this->namespace, '/' . $this->rest_base . '/settings', [
|
||||
[
|
||||
@@ -59,7 +63,7 @@ class StoreController extends WP_REST_Controller {
|
||||
'permission_callback' => [$this, 'check_permission'],
|
||||
],
|
||||
]);
|
||||
|
||||
|
||||
// GET /woonoow/v1/store/countries
|
||||
register_rest_route($this->namespace, '/' . $this->rest_base . '/countries', [
|
||||
[
|
||||
@@ -68,7 +72,7 @@ class StoreController extends WP_REST_Controller {
|
||||
'permission_callback' => [$this, 'check_permission'],
|
||||
],
|
||||
]);
|
||||
|
||||
|
||||
// GET /woonoow/v1/store/timezones
|
||||
register_rest_route($this->namespace, '/' . $this->rest_base . '/timezones', [
|
||||
[
|
||||
@@ -77,7 +81,7 @@ class StoreController extends WP_REST_Controller {
|
||||
'permission_callback' => [$this, 'check_permission'],
|
||||
],
|
||||
]);
|
||||
|
||||
|
||||
// GET /woonoow/v1/store/currencies
|
||||
register_rest_route($this->namespace, '/' . $this->rest_base . '/currencies', [
|
||||
[
|
||||
@@ -86,7 +90,7 @@ class StoreController extends WP_REST_Controller {
|
||||
'permission_callback' => [$this, 'check_permission'],
|
||||
],
|
||||
]);
|
||||
|
||||
|
||||
// GET /woonoow/v1/store/customer-settings
|
||||
register_rest_route($this->namespace, '/' . $this->rest_base . '/customer-settings', [
|
||||
[
|
||||
@@ -95,7 +99,7 @@ class StoreController extends WP_REST_Controller {
|
||||
'permission_callback' => [$this, 'check_permission'],
|
||||
],
|
||||
]);
|
||||
|
||||
|
||||
// POST /woonoow/v1/store/customer-settings
|
||||
register_rest_route($this->namespace, '/' . $this->rest_base . '/customer-settings', [
|
||||
[
|
||||
@@ -104,15 +108,34 @@ class StoreController extends WP_REST_Controller {
|
||||
'permission_callback' => [$this, 'check_permission'],
|
||||
],
|
||||
]);
|
||||
|
||||
// GET /woonoow/v1/store/security-settings
|
||||
register_rest_route($this->namespace, '/' . $this->rest_base . '/security-settings', [
|
||||
[
|
||||
'methods' => WP_REST_Server::READABLE,
|
||||
'callback' => [$this, 'get_security_settings'],
|
||||
'permission_callback' => [$this, 'check_permission'],
|
||||
],
|
||||
]);
|
||||
|
||||
// POST /woonoow/v1/store/security-settings
|
||||
register_rest_route($this->namespace, '/' . $this->rest_base . '/security-settings', [
|
||||
[
|
||||
'methods' => WP_REST_Server::EDITABLE,
|
||||
'callback' => [$this, 'save_security_settings'],
|
||||
'permission_callback' => [$this, 'check_permission'],
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get store branding (PUBLIC - for login page)
|
||||
*
|
||||
* @param WP_REST_Request $request Request object
|
||||
* @return WP_REST_Response Response object
|
||||
*/
|
||||
public function get_branding(WP_REST_Request $request) {
|
||||
public function get_branding(WP_REST_Request $request)
|
||||
{
|
||||
$branding = [
|
||||
'store_name' => get_option('woonoow_store_name', '') ?: get_option('blogname', 'WooNooW'),
|
||||
'store_logo' => get_option('woonoow_store_logo', ''),
|
||||
@@ -120,26 +143,27 @@ class StoreController extends WP_REST_Controller {
|
||||
'store_icon' => get_option('woonoow_store_icon', ''),
|
||||
'store_tagline' => get_option('woonoow_store_tagline', ''),
|
||||
];
|
||||
|
||||
|
||||
$response = rest_ensure_response($branding);
|
||||
$response->header('Cache-Control', 'max-age=300'); // Cache for 5 minutes
|
||||
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get store settings
|
||||
*
|
||||
* @param WP_REST_Request $request Request object
|
||||
* @return WP_REST_Response|WP_Error Response object or error
|
||||
*/
|
||||
public function get_settings(WP_REST_Request $request) {
|
||||
public function get_settings(WP_REST_Request $request)
|
||||
{
|
||||
try {
|
||||
$settings = StoreSettingsProvider::get_settings();
|
||||
|
||||
|
||||
$response = rest_ensure_response($settings);
|
||||
$response->header('Cache-Control', 'max-age=60');
|
||||
|
||||
|
||||
return $response;
|
||||
} catch (\Exception $e) {
|
||||
return new WP_Error(
|
||||
@@ -149,16 +173,17 @@ class StoreController extends WP_REST_Controller {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save store settings
|
||||
*
|
||||
* @param WP_REST_Request $request Request object
|
||||
* @return WP_REST_Response|WP_Error Response object or error
|
||||
*/
|
||||
public function save_settings(WP_REST_Request $request) {
|
||||
public function save_settings(WP_REST_Request $request)
|
||||
{
|
||||
$settings = $request->get_json_params();
|
||||
|
||||
|
||||
if (empty($settings)) {
|
||||
return new WP_Error(
|
||||
'missing_settings',
|
||||
@@ -166,10 +191,10 @@ class StoreController extends WP_REST_Controller {
|
||||
['status' => 400]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
$result = StoreSettingsProvider::save_settings($settings);
|
||||
|
||||
|
||||
if (!$result) {
|
||||
return new WP_Error(
|
||||
'save_failed',
|
||||
@@ -177,7 +202,7 @@ class StoreController extends WP_REST_Controller {
|
||||
['status' => 500]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
return rest_ensure_response([
|
||||
'success' => true,
|
||||
'message' => 'Settings saved successfully',
|
||||
@@ -191,20 +216,21 @@ class StoreController extends WP_REST_Controller {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get countries
|
||||
*
|
||||
* @param WP_REST_Request $request Request object
|
||||
* @return WP_REST_Response|WP_Error Response object or error
|
||||
*/
|
||||
public function get_countries(WP_REST_Request $request) {
|
||||
public function get_countries(WP_REST_Request $request)
|
||||
{
|
||||
try {
|
||||
$countries = StoreSettingsProvider::get_countries();
|
||||
|
||||
|
||||
$response = rest_ensure_response($countries);
|
||||
$response->header('Cache-Control', 'max-age=3600'); // Cache for 1 hour
|
||||
|
||||
|
||||
return $response;
|
||||
} catch (\Exception $e) {
|
||||
return new WP_Error(
|
||||
@@ -214,20 +240,21 @@ class StoreController extends WP_REST_Controller {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get timezones
|
||||
*
|
||||
* @param WP_REST_Request $request Request object
|
||||
* @return WP_REST_Response|WP_Error Response object or error
|
||||
*/
|
||||
public function get_timezones(WP_REST_Request $request) {
|
||||
public function get_timezones(WP_REST_Request $request)
|
||||
{
|
||||
try {
|
||||
$timezones = StoreSettingsProvider::get_timezones();
|
||||
|
||||
|
||||
$response = rest_ensure_response($timezones);
|
||||
$response->header('Cache-Control', 'max-age=3600'); // Cache for 1 hour
|
||||
|
||||
|
||||
return $response;
|
||||
} catch (\Exception $e) {
|
||||
return new WP_Error(
|
||||
@@ -237,20 +264,21 @@ class StoreController extends WP_REST_Controller {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get currencies
|
||||
*
|
||||
* @param WP_REST_Request $request Request object
|
||||
* @return WP_REST_Response|WP_Error Response object or error
|
||||
*/
|
||||
public function get_currencies(WP_REST_Request $request) {
|
||||
public function get_currencies(WP_REST_Request $request)
|
||||
{
|
||||
try {
|
||||
$currencies = StoreSettingsProvider::get_currencies();
|
||||
|
||||
|
||||
$response = rest_ensure_response($currencies);
|
||||
$response->header('Cache-Control', 'max-age=3600'); // Cache for 1 hour
|
||||
|
||||
|
||||
return $response;
|
||||
} catch (\Exception $e) {
|
||||
return new WP_Error(
|
||||
@@ -260,20 +288,21 @@ class StoreController extends WP_REST_Controller {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get customer settings
|
||||
*
|
||||
* @param WP_REST_Request $request Request object
|
||||
* @return WP_REST_Response|WP_Error Response object or error
|
||||
*/
|
||||
public function get_customer_settings(WP_REST_Request $request) {
|
||||
public function get_customer_settings(WP_REST_Request $request)
|
||||
{
|
||||
try {
|
||||
$settings = CustomerSettingsProvider::get_settings();
|
||||
|
||||
|
||||
$response = rest_ensure_response($settings);
|
||||
$response->header('Cache-Control', 'max-age=60');
|
||||
|
||||
|
||||
return $response;
|
||||
} catch (\Exception $e) {
|
||||
return new WP_Error(
|
||||
@@ -283,17 +312,18 @@ class StoreController extends WP_REST_Controller {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save customer settings
|
||||
*
|
||||
* @param WP_REST_Request $request Request object
|
||||
* @return WP_REST_Response|WP_Error Response object or error
|
||||
*/
|
||||
public function save_customer_settings(WP_REST_Request $request) {
|
||||
public function save_customer_settings(WP_REST_Request $request)
|
||||
{
|
||||
try {
|
||||
$settings = $request->get_json_params();
|
||||
|
||||
|
||||
if (empty($settings)) {
|
||||
return new WP_Error(
|
||||
'invalid_settings',
|
||||
@@ -301,9 +331,9 @@ class StoreController extends WP_REST_Controller {
|
||||
['status' => 400]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
$updated = CustomerSettingsProvider::update_settings($settings);
|
||||
|
||||
|
||||
if (!$updated) {
|
||||
return new WP_Error(
|
||||
'update_failed',
|
||||
@@ -311,16 +341,15 @@ class StoreController extends WP_REST_Controller {
|
||||
['status' => 500]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Return updated settings
|
||||
$new_settings = CustomerSettingsProvider::get_settings();
|
||||
|
||||
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'message' => __('Customer settings updated successfully', 'woonoow'),
|
||||
'settings' => $new_settings,
|
||||
], 200);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
return new WP_Error(
|
||||
'save_customer_settings_failed',
|
||||
@@ -329,13 +358,84 @@ class StoreController extends WP_REST_Controller {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get security settings
|
||||
*
|
||||
* @param WP_REST_Request $request Request object
|
||||
* @return WP_REST_Response|WP_Error Response object or error
|
||||
*/
|
||||
public function get_security_settings(WP_REST_Request $request)
|
||||
{
|
||||
try {
|
||||
$settings = SecuritySettingsProvider::get_settings();
|
||||
|
||||
$response = rest_ensure_response($settings);
|
||||
$response->header('Cache-Control', 'max-age=60');
|
||||
|
||||
return $response;
|
||||
} catch (\Exception $e) {
|
||||
return new WP_Error(
|
||||
'get_security_settings_failed',
|
||||
$e->getMessage(),
|
||||
['status' => 500]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save security settings
|
||||
*
|
||||
* @param WP_REST_Request $request Request object
|
||||
* @return WP_REST_Response|WP_Error Response object or error
|
||||
*/
|
||||
public function save_security_settings(WP_REST_Request $request)
|
||||
{
|
||||
try {
|
||||
$settings = $request->get_json_params();
|
||||
|
||||
if (empty($settings)) {
|
||||
return new WP_Error(
|
||||
'invalid_settings',
|
||||
__('Invalid settings data', 'woonoow'),
|
||||
['status' => 400]
|
||||
);
|
||||
}
|
||||
|
||||
$updated = SecuritySettingsProvider::update_settings($settings);
|
||||
|
||||
if (!$updated) {
|
||||
return new WP_Error(
|
||||
'update_failed',
|
||||
__('Failed to update security settings', 'woonoow'),
|
||||
['status' => 500]
|
||||
);
|
||||
}
|
||||
|
||||
// Return updated settings
|
||||
$new_settings = SecuritySettingsProvider::get_settings();
|
||||
|
||||
return new WP_REST_Response([
|
||||
'success' => true,
|
||||
'message' => __('Security settings updated successfully', 'woonoow'),
|
||||
'settings' => $new_settings,
|
||||
], 200);
|
||||
} catch (\Exception $e) {
|
||||
return new WP_Error(
|
||||
'save_security_settings_failed',
|
||||
$e->getMessage(),
|
||||
['status' => 500]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user has permission
|
||||
*
|
||||
* @return bool True if user has permission
|
||||
*/
|
||||
public function check_permission() {
|
||||
public function check_permission()
|
||||
{
|
||||
// Check WooCommerce capability first, fallback to manage_options
|
||||
return current_user_can('manage_woocommerce') || current_user_can('manage_options');
|
||||
}
|
||||
|
||||
@@ -471,6 +471,31 @@ class SubscriptionsController
|
||||
}
|
||||
$enriched['billing_schedule'] = sprintf(__('Every %s%s', 'woonoow'), $interval, $period);
|
||||
|
||||
// Add payment method title
|
||||
$payment_title = $subscription->payment_method; // Default to ID
|
||||
|
||||
// 1. Try from payment_meta (stored snapshot)
|
||||
if (!empty($subscription->payment_meta)) {
|
||||
$meta = json_decode($subscription->payment_meta, true);
|
||||
if (isset($meta['method_title']) && !empty($meta['method_title'])) {
|
||||
$payment_title = $meta['method_title'];
|
||||
}
|
||||
}
|
||||
|
||||
// 2. If it looks like an ID (no spaces, lowercase), try to get fresh title from gateway
|
||||
if ($payment_title === $subscription->payment_method && function_exists('WC')) {
|
||||
$gateways_handler = WC()->payment_gateways();
|
||||
if ($gateways_handler) {
|
||||
$gateways = $gateways_handler->payment_gateways();
|
||||
if (isset($gateways[$subscription->payment_method])) {
|
||||
$gw = $gateways[$subscription->payment_method];
|
||||
$payment_title = $gw->get_title() ?: $gw->method_title;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$enriched['payment_method_title'] = $payment_title;
|
||||
|
||||
return $enriched;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user