feat: Tax route fix + Local Pickup + Email/Notifications settings

## 1. Fixed Tax Settings Route 
- Changed /settings/taxes → /settings/tax in nav tree
- Now matches App.tsx route
- Tax page now loads correctly

## 2. Advanced Local Pickup 
Frontend (LocalPickup.tsx):
- Add/edit/delete pickup locations
- Enable/disable locations
- Full address fields (street, city, state, postcode)
- Phone number and business hours
- Clean modal UI for adding locations

Backend (PickupLocationsController.php):
- GET /settings/pickup-locations
- POST /settings/pickup-locations (create)
- POST /settings/pickup-locations/:id (update)
- DELETE /settings/pickup-locations/:id
- POST /settings/pickup-locations/:id/toggle
- Stores in wp_options as array

## 3. Email/Notifications Settings 
Frontend (Notifications.tsx):
- List all WooCommerce emails
- Separate customer vs admin emails
- Enable/disable toggle for each email
- Show from name/email
- Link to WooCommerce for advanced config

Backend (EmailController.php):
- GET /settings/emails - List all emails
- POST /settings/emails/:id/toggle - Enable/disable
- Uses WC()->mailer()->get_emails()
- Auto-detects recipient type (customer/admin)

## Features:
 Simple, non-tech-savvy UI
 All CRUD operations
 Real-time updates
 Links to WooCommerce for advanced settings
 Mobile responsive

Next: Test all settings pages
This commit is contained in:
dwindown
2025-11-09 23:44:24 +07:00
parent 603d94b73c
commit 5fb5eda9c3
7 changed files with 1009 additions and 2 deletions

View File

@@ -0,0 +1,144 @@
<?php
/**
* Email Settings REST API Controller
*
* @package WooNooW
*/
namespace WooNooW\Api;
use WP_REST_Controller;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;
class EmailController extends WP_REST_Controller {
/**
* Register routes
*/
public function register_routes() {
$namespace = 'woonoow/v1';
// Get email settings
register_rest_route(
$namespace,
'/settings/emails',
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_settings' ),
'permission_callback' => array( $this, 'check_permission' ),
)
);
// Toggle email
register_rest_route(
$namespace,
'/settings/emails/(?P<email_id>[a-zA-Z0-9_-]+)/toggle',
array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => array( $this, 'toggle_email' ),
'permission_callback' => array( $this, 'check_permission' ),
)
);
}
/**
* Check permission
*/
public function check_permission() {
return current_user_can( 'manage_woocommerce' );
}
/**
* Get email settings
*/
public function get_settings( WP_REST_Request $request ) {
try {
$email_settings = array();
$emails = \WC()->mailer()->get_emails();
foreach ( $emails as $email ) {
$recipient = 'customer';
// Determine recipient type
if ( strpos( $email->id, 'admin' ) !== false ||
strpos( $email->id, 'new_order' ) !== false ||
strpos( $email->id, 'cancelled_order' ) !== false ||
strpos( $email->id, 'failed_order' ) !== false ) {
$recipient = 'admin';
}
$email_settings[] = array(
'id' => $email->id,
'title' => $email->get_title(),
'description' => $email->get_description(),
'enabled' => $email->is_enabled() ? 'yes' : 'no',
'recipient' => $recipient,
);
}
$settings = array(
'emails' => $email_settings,
'from_name' => get_option( 'woocommerce_email_from_name' ),
'from_email' => get_option( 'woocommerce_email_from_address' ),
);
return new WP_REST_Response( $settings, 200 );
} catch ( \Exception $e ) {
return new WP_REST_Response(
array(
'error' => 'fetch_failed',
'message' => $e->getMessage(),
),
500
);
}
}
/**
* Toggle email
*/
public function toggle_email( WP_REST_Request $request ) {
try {
$email_id = $request->get_param( 'email_id' );
$enabled = rest_sanitize_boolean( $request->get_param( 'enabled' ) );
$emails = \WC()->mailer()->get_emails();
if ( ! isset( $emails[ $email_id ] ) ) {
return new WP_REST_Response(
array(
'error' => 'not_found',
'message' => __( 'Email not found', 'woonoow' ),
),
404
);
}
$email = $emails[ $email_id ];
// Update email settings
$email->update_option( 'enabled', $enabled ? 'yes' : 'no' );
return new WP_REST_Response(
array(
'success' => true,
'enabled' => $enabled,
'message' => $enabled
? __( 'Email enabled', 'woonoow' )
: __( 'Email disabled', 'woonoow' ),
),
200
);
} catch ( \Exception $e ) {
return new WP_REST_Response(
array(
'error' => 'toggle_failed',
'message' => $e->getMessage(),
),
500
);
}
}
}

View File

@@ -0,0 +1,248 @@
<?php
/**
* Pickup Locations REST API Controller
*
* @package WooNooW
*/
namespace WooNooW\Api;
use WP_REST_Controller;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;
class PickupLocationsController extends WP_REST_Controller {
/**
* Register routes
*/
public function register_routes() {
$namespace = 'woonoow/v1';
// Get all pickup locations
register_rest_route(
$namespace,
'/settings/pickup-locations',
array(
array(
'methods' => WP_REST_Server::READABLE,
'callback' => array( $this, 'get_locations' ),
'permission_callback' => array( $this, 'check_permission' ),
),
array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => array( $this, 'create_location' ),
'permission_callback' => array( $this, 'check_permission' ),
),
)
);
// Update/Delete specific location
register_rest_route(
$namespace,
'/settings/pickup-locations/(?P<id>[a-zA-Z0-9_-]+)',
array(
array(
'methods' => WP_REST_Server::EDITABLE,
'callback' => array( $this, 'update_location' ),
'permission_callback' => array( $this, 'check_permission' ),
),
array(
'methods' => WP_REST_Server::DELETABLE,
'callback' => array( $this, 'delete_location' ),
'permission_callback' => array( $this, 'check_permission' ),
),
)
);
// Toggle location
register_rest_route(
$namespace,
'/settings/pickup-locations/(?P<id>[a-zA-Z0-9_-]+)/toggle',
array(
'methods' => WP_REST_Server::CREATABLE,
'callback' => array( $this, 'toggle_location' ),
'permission_callback' => array( $this, 'check_permission' ),
)
);
}
/**
* Check permission
*/
public function check_permission() {
return current_user_can( 'manage_woocommerce' );
}
/**
* Get all pickup locations
*/
public function get_locations( WP_REST_Request $request ) {
$locations = get_option( 'woonoow_pickup_locations', array() );
return new WP_REST_Response( array_values( $locations ), 200 );
}
/**
* Create pickup location
*/
public function create_location( WP_REST_Request $request ) {
try {
$locations = get_option( 'woonoow_pickup_locations', array() );
$id = uniqid( 'loc_' );
$location = array(
'id' => $id,
'name' => sanitize_text_field( $request->get_param( 'name' ) ),
'address' => sanitize_text_field( $request->get_param( 'address' ) ),
'city' => sanitize_text_field( $request->get_param( 'city' ) ),
'state' => sanitize_text_field( $request->get_param( 'state' ) ),
'postcode' => sanitize_text_field( $request->get_param( 'postcode' ) ),
'phone' => sanitize_text_field( $request->get_param( 'phone' ) ),
'hours' => sanitize_text_field( $request->get_param( 'hours' ) ),
'enabled' => true,
);
$locations[ $id ] = $location;
update_option( 'woonoow_pickup_locations', $locations );
return new WP_REST_Response( $location, 201 );
} catch ( \Exception $e ) {
return new WP_REST_Response(
array(
'error' => 'create_failed',
'message' => $e->getMessage(),
),
500
);
}
}
/**
* Update pickup location
*/
public function update_location( WP_REST_Request $request ) {
try {
$id = $request->get_param( 'id' );
$locations = get_option( 'woonoow_pickup_locations', array() );
if ( ! isset( $locations[ $id ] ) ) {
return new WP_REST_Response(
array(
'error' => 'not_found',
'message' => __( 'Location not found', 'woonoow' ),
),
404
);
}
$location = array(
'id' => $id,
'name' => sanitize_text_field( $request->get_param( 'name' ) ),
'address' => sanitize_text_field( $request->get_param( 'address' ) ),
'city' => sanitize_text_field( $request->get_param( 'city' ) ),
'state' => sanitize_text_field( $request->get_param( 'state' ) ),
'postcode' => sanitize_text_field( $request->get_param( 'postcode' ) ),
'phone' => sanitize_text_field( $request->get_param( 'phone' ) ),
'hours' => sanitize_text_field( $request->get_param( 'hours' ) ),
'enabled' => $locations[ $id ]['enabled'], // Preserve enabled status
);
$locations[ $id ] = $location;
update_option( 'woonoow_pickup_locations', $locations );
return new WP_REST_Response( $location, 200 );
} catch ( \Exception $e ) {
return new WP_REST_Response(
array(
'error' => 'update_failed',
'message' => $e->getMessage(),
),
500
);
}
}
/**
* Delete pickup location
*/
public function delete_location( WP_REST_Request $request ) {
try {
$id = $request->get_param( 'id' );
$locations = get_option( 'woonoow_pickup_locations', array() );
if ( ! isset( $locations[ $id ] ) ) {
return new WP_REST_Response(
array(
'error' => 'not_found',
'message' => __( 'Location not found', 'woonoow' ),
),
404
);
}
unset( $locations[ $id ] );
update_option( 'woonoow_pickup_locations', $locations );
return new WP_REST_Response(
array(
'success' => true,
'message' => __( 'Location deleted', 'woonoow' ),
),
200
);
} catch ( \Exception $e ) {
return new WP_REST_Response(
array(
'error' => 'delete_failed',
'message' => $e->getMessage(),
),
500
);
}
}
/**
* Toggle pickup location
*/
public function toggle_location( WP_REST_Request $request ) {
try {
$id = $request->get_param( 'id' );
$enabled = rest_sanitize_boolean( $request->get_param( 'enabled' ) );
$locations = get_option( 'woonoow_pickup_locations', array() );
if ( ! isset( $locations[ $id ] ) ) {
return new WP_REST_Response(
array(
'error' => 'not_found',
'message' => __( 'Location not found', 'woonoow' ),
),
404
);
}
$locations[ $id ]['enabled'] = $enabled;
update_option( 'woonoow_pickup_locations', $locations );
return new WP_REST_Response(
array(
'success' => true,
'enabled' => $enabled,
'message' => $enabled
? __( 'Location enabled', 'woonoow' )
: __( 'Location disabled', 'woonoow' ),
),
200
);
} catch ( \Exception $e ) {
return new WP_REST_Response(
array(
'error' => 'toggle_failed',
'message' => $e->getMessage(),
),
500
);
}
}
}

View File

@@ -11,6 +11,8 @@ use WooNooW\API\PaymentsController;
use WooNooW\API\StoreController;
use WooNooW\Api\ShippingController;
use WooNooW\Api\TaxController;
use WooNooW\Api\PickupLocationsController;
use WooNooW\Api\EmailController;
class Routes {
public static function init() {
@@ -59,6 +61,14 @@ class Routes {
// Tax controller
$tax_controller = new TaxController();
$tax_controller->register_routes();
// Pickup locations controller
$pickup_controller = new PickupLocationsController();
$pickup_controller->register_routes();
// Email controller
$email_controller = new EmailController();
$email_controller->register_routes();
});
}
}