feat: Add Store Settings backend with full countries/timezones
✅ StoreSettingsProvider.php: - get_countries() - All WooCommerce countries - get_timezones() - All PHP timezones with UTC offsets - get_currencies() - All WooCommerce currencies with symbols - get_settings() - Current store settings - save_settings() - Save store settings ✅ StoreController.php: - GET /woonoow/v1/store/settings - POST /woonoow/v1/store/settings - GET /woonoow/v1/store/countries (200+ countries) - GET /woonoow/v1/store/timezones (400+ timezones) - GET /woonoow/v1/store/currencies (100+ currencies) - Response caching (1 hour for static data) 🔌 Integration: - Registered in Api/Routes.php - Permission checks (manage_woocommerce) - Error handling Next: Update Store.tsx to use real API
This commit is contained in:
@@ -8,6 +8,7 @@ use WooNooW\Api\OrdersController;
|
|||||||
use WooNooW\Api\AnalyticsController;
|
use WooNooW\Api\AnalyticsController;
|
||||||
use WooNooW\Api\AuthController;
|
use WooNooW\Api\AuthController;
|
||||||
use WooNooW\API\PaymentsController;
|
use WooNooW\API\PaymentsController;
|
||||||
|
use WooNooW\API\StoreController;
|
||||||
|
|
||||||
class Routes {
|
class Routes {
|
||||||
public static function init() {
|
public static function init() {
|
||||||
@@ -44,6 +45,10 @@ class Routes {
|
|||||||
// Payments controller
|
// Payments controller
|
||||||
$payments_controller = new PaymentsController();
|
$payments_controller = new PaymentsController();
|
||||||
$payments_controller->register_routes();
|
$payments_controller->register_routes();
|
||||||
|
|
||||||
|
// Store controller
|
||||||
|
$store_controller = new StoreController();
|
||||||
|
$store_controller->register_routes();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
223
includes/Api/StoreController.php
Normal file
223
includes/Api/StoreController.php
Normal file
@@ -0,0 +1,223 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Store REST API Controller
|
||||||
|
*
|
||||||
|
* Provides REST endpoints for store settings management.
|
||||||
|
*
|
||||||
|
* @package WooNooW
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace WooNooW\API;
|
||||||
|
|
||||||
|
use WooNooW\Compat\StoreSettingsProvider;
|
||||||
|
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 {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Namespace
|
||||||
|
*/
|
||||||
|
protected $namespace = 'woonoow/v1';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rest base
|
||||||
|
*/
|
||||||
|
protected $rest_base = 'store';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register routes
|
||||||
|
*/
|
||||||
|
public function register_routes() {
|
||||||
|
// GET /woonoow/v1/store/settings
|
||||||
|
register_rest_route($this->namespace, '/' . $this->rest_base . '/settings', [
|
||||||
|
[
|
||||||
|
'methods' => WP_REST_Server::READABLE,
|
||||||
|
'callback' => [$this, 'get_settings'],
|
||||||
|
'permission_callback' => [$this, 'check_permission'],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
// POST /woonoow/v1/store/settings
|
||||||
|
register_rest_route($this->namespace, '/' . $this->rest_base . '/settings', [
|
||||||
|
[
|
||||||
|
'methods' => WP_REST_Server::EDITABLE,
|
||||||
|
'callback' => [$this, 'save_settings'],
|
||||||
|
'permission_callback' => [$this, 'check_permission'],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
// GET /woonoow/v1/store/countries
|
||||||
|
register_rest_route($this->namespace, '/' . $this->rest_base . '/countries', [
|
||||||
|
[
|
||||||
|
'methods' => WP_REST_Server::READABLE,
|
||||||
|
'callback' => [$this, 'get_countries'],
|
||||||
|
'permission_callback' => [$this, 'check_permission'],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
// GET /woonoow/v1/store/timezones
|
||||||
|
register_rest_route($this->namespace, '/' . $this->rest_base . '/timezones', [
|
||||||
|
[
|
||||||
|
'methods' => WP_REST_Server::READABLE,
|
||||||
|
'callback' => [$this, 'get_timezones'],
|
||||||
|
'permission_callback' => [$this, 'check_permission'],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
|
||||||
|
// GET /woonoow/v1/store/currencies
|
||||||
|
register_rest_route($this->namespace, '/' . $this->rest_base . '/currencies', [
|
||||||
|
[
|
||||||
|
'methods' => WP_REST_Server::READABLE,
|
||||||
|
'callback' => [$this, 'get_currencies'],
|
||||||
|
'permission_callback' => [$this, 'check_permission'],
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
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(
|
||||||
|
'get_settings_failed',
|
||||||
|
$e->getMessage(),
|
||||||
|
['status' => 500]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
$settings = $request->get_json_params();
|
||||||
|
|
||||||
|
if (empty($settings)) {
|
||||||
|
return new WP_Error(
|
||||||
|
'missing_settings',
|
||||||
|
'No settings provided',
|
||||||
|
['status' => 400]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$result = StoreSettingsProvider::save_settings($settings);
|
||||||
|
|
||||||
|
if (!$result) {
|
||||||
|
return new WP_Error(
|
||||||
|
'save_failed',
|
||||||
|
'Failed to save settings',
|
||||||
|
['status' => 500]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return rest_ensure_response([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'Settings saved successfully',
|
||||||
|
'settings' => StoreSettingsProvider::get_settings(),
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return new WP_Error(
|
||||||
|
'save_settings_failed',
|
||||||
|
$e->getMessage(),
|
||||||
|
['status' => 500]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
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(
|
||||||
|
'get_countries_failed',
|
||||||
|
$e->getMessage(),
|
||||||
|
['status' => 500]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
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(
|
||||||
|
'get_timezones_failed',
|
||||||
|
$e->getMessage(),
|
||||||
|
['status' => 500]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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) {
|
||||||
|
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(
|
||||||
|
'get_currencies_failed',
|
||||||
|
$e->getMessage(),
|
||||||
|
['status' => 500]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check permission
|
||||||
|
*
|
||||||
|
* @return bool True if user has permission
|
||||||
|
*/
|
||||||
|
public function check_permission() {
|
||||||
|
return current_user_can('manage_woocommerce');
|
||||||
|
}
|
||||||
|
}
|
||||||
169
includes/Compat/StoreSettingsProvider.php
Normal file
169
includes/Compat/StoreSettingsProvider.php
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Store Settings Provider
|
||||||
|
*
|
||||||
|
* Provides store settings data including countries, timezones, currencies, etc.
|
||||||
|
*
|
||||||
|
* @package WooNooW
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace WooNooW\Compat;
|
||||||
|
|
||||||
|
class StoreSettingsProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all countries from WooCommerce
|
||||||
|
*
|
||||||
|
* @return array List of countries
|
||||||
|
*/
|
||||||
|
public static function get_countries(): array {
|
||||||
|
if (!class_exists('WC_Countries')) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$wc_countries = new \WC_Countries();
|
||||||
|
$countries = $wc_countries->get_countries();
|
||||||
|
|
||||||
|
$formatted = [];
|
||||||
|
foreach ($countries as $code => $name) {
|
||||||
|
$formatted[] = [
|
||||||
|
'code' => $code,
|
||||||
|
'name' => $name,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $formatted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all timezones
|
||||||
|
*
|
||||||
|
* @return array List of timezones
|
||||||
|
*/
|
||||||
|
public static function get_timezones(): array {
|
||||||
|
$timezones = timezone_identifiers_list();
|
||||||
|
$formatted = [];
|
||||||
|
|
||||||
|
foreach ($timezones as $timezone) {
|
||||||
|
// Group by continent
|
||||||
|
$parts = explode('/', $timezone);
|
||||||
|
$continent = $parts[0] ?? 'Other';
|
||||||
|
|
||||||
|
if (!isset($formatted[$continent])) {
|
||||||
|
$formatted[$continent] = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format display name
|
||||||
|
$display = str_replace('_', ' ', $timezone);
|
||||||
|
|
||||||
|
// Get UTC offset
|
||||||
|
try {
|
||||||
|
$tz = new \DateTimeZone($timezone);
|
||||||
|
$now = new \DateTime('now', $tz);
|
||||||
|
$offset = $tz->getOffset($now);
|
||||||
|
$hours = floor($offset / 3600);
|
||||||
|
$minutes = abs(floor(($offset % 3600) / 60));
|
||||||
|
$offset_string = sprintf('UTC%+d:%02d', $hours, $minutes);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
$offset_string = 'UTC';
|
||||||
|
}
|
||||||
|
|
||||||
|
$formatted[$continent][] = [
|
||||||
|
'value' => $timezone,
|
||||||
|
'label' => $display,
|
||||||
|
'offset' => $offset_string,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $formatted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all currencies from WooCommerce
|
||||||
|
*
|
||||||
|
* @return array List of currencies
|
||||||
|
*/
|
||||||
|
public static function get_currencies(): array {
|
||||||
|
if (!function_exists('get_woocommerce_currencies')) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
$currencies = get_woocommerce_currencies();
|
||||||
|
$formatted = [];
|
||||||
|
|
||||||
|
foreach ($currencies as $code => $name) {
|
||||||
|
$symbol = get_woocommerce_currency_symbol($code);
|
||||||
|
|
||||||
|
$formatted[] = [
|
||||||
|
'code' => $code,
|
||||||
|
'name' => $name,
|
||||||
|
'symbol' => $symbol,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $formatted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get store settings
|
||||||
|
*
|
||||||
|
* @return array Store settings
|
||||||
|
*/
|
||||||
|
public static function get_settings(): array {
|
||||||
|
return [
|
||||||
|
'store_name' => get_option('blogname', ''),
|
||||||
|
'contact_email' => get_option('admin_email', ''),
|
||||||
|
'support_email' => get_option('woocommerce_email_from_address', ''),
|
||||||
|
'phone' => get_option('woocommerce_store_phone', ''),
|
||||||
|
'country' => get_option('woocommerce_default_country', ''),
|
||||||
|
'address' => get_option('woocommerce_store_address', ''),
|
||||||
|
'address_2' => get_option('woocommerce_store_address_2', ''),
|
||||||
|
'city' => get_option('woocommerce_store_city', ''),
|
||||||
|
'postcode' => get_option('woocommerce_store_postcode', ''),
|
||||||
|
'currency' => get_option('woocommerce_currency', 'USD'),
|
||||||
|
'currency_position' => get_option('woocommerce_currency_pos', 'left'),
|
||||||
|
'thousand_separator' => get_option('woocommerce_price_thousand_sep', ','),
|
||||||
|
'decimal_separator' => get_option('woocommerce_price_decimal_sep', '.'),
|
||||||
|
'number_of_decimals' => (int) get_option('woocommerce_price_num_decimals', 2),
|
||||||
|
'timezone' => get_option('timezone_string', 'UTC'),
|
||||||
|
'weight_unit' => get_option('woocommerce_weight_unit', 'kg'),
|
||||||
|
'dimension_unit' => get_option('woocommerce_dimension_unit', 'cm'),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save store settings
|
||||||
|
*
|
||||||
|
* @param array $settings Settings to save
|
||||||
|
* @return bool True on success
|
||||||
|
*/
|
||||||
|
public static function save_settings(array $settings): bool {
|
||||||
|
$mapping = [
|
||||||
|
'store_name' => 'blogname',
|
||||||
|
'contact_email' => 'admin_email',
|
||||||
|
'support_email' => 'woocommerce_email_from_address',
|
||||||
|
'phone' => 'woocommerce_store_phone',
|
||||||
|
'country' => 'woocommerce_default_country',
|
||||||
|
'address' => 'woocommerce_store_address',
|
||||||
|
'address_2' => 'woocommerce_store_address_2',
|
||||||
|
'city' => 'woocommerce_store_city',
|
||||||
|
'postcode' => 'woocommerce_store_postcode',
|
||||||
|
'currency' => 'woocommerce_currency',
|
||||||
|
'currency_position' => 'woocommerce_currency_pos',
|
||||||
|
'thousand_separator' => 'woocommerce_price_thousand_sep',
|
||||||
|
'decimal_separator' => 'woocommerce_price_decimal_sep',
|
||||||
|
'number_of_decimals' => 'woocommerce_price_num_decimals',
|
||||||
|
'timezone' => 'timezone_string',
|
||||||
|
'weight_unit' => 'woocommerce_weight_unit',
|
||||||
|
'dimension_unit' => 'woocommerce_dimension_unit',
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($settings as $key => $value) {
|
||||||
|
if (isset($mapping[$key])) {
|
||||||
|
update_option($mapping[$key], $value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user