From bc7206f1cc9de44aa2db05614cd68930d95f6441 Mon Sep 17 00:00:00 2001 From: dwindown Date: Sat, 8 Nov 2025 21:27:34 +0700 Subject: [PATCH] feat: Add Shipping API controller MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created backend API for fetching WooCommerce shipping zones. New Files: - includes/Api/ShippingController.php Features: ✅ GET /settings/shipping/zones endpoint ✅ Fetches all WooCommerce shipping zones ✅ Includes shipping methods for each zone ✅ Handles "Rest of the World" zone (zone 0) ✅ Returns formatted region names ✅ Returns method costs (Free, Calculated, or price) ✅ Permission check: manage_woocommerce Data Structure: - id: Zone ID - name: Zone name - order: Display order - regions: Comma-separated region names - rates: Array of shipping methods - id: Method instance ID - name: Method title - price: Formatted price or "Free"/"Calculated" - enabled: Boolean Integration: - Registered in Routes.php - Uses WC_Shipping_Zones API - Compatible with all WooCommerce shipping methods --- includes/Api/Routes.php | 5 + includes/Api/ShippingController.php | 153 ++++++++++++++++++++++++++++ 2 files changed, 158 insertions(+) create mode 100644 includes/Api/ShippingController.php diff --git a/includes/Api/Routes.php b/includes/Api/Routes.php index 0f9d492..737fa40 100644 --- a/includes/Api/Routes.php +++ b/includes/Api/Routes.php @@ -9,6 +9,7 @@ use WooNooW\Api\AnalyticsController; use WooNooW\Api\AuthController; use WooNooW\API\PaymentsController; use WooNooW\API\StoreController; +use WooNooW\Api\ShippingController; class Routes { public static function init() { @@ -49,6 +50,10 @@ class Routes { // Store controller $store_controller = new StoreController(); $store_controller->register_routes(); + + // Shipping controller + $shipping_controller = new ShippingController(); + $shipping_controller->register_routes(); }); } } diff --git a/includes/Api/ShippingController.php b/includes/Api/ShippingController.php new file mode 100644 index 0000000..4d335e1 --- /dev/null +++ b/includes/Api/ShippingController.php @@ -0,0 +1,153 @@ +namespace, + '/' . $this->rest_base . '/zones', + array( + array( + 'methods' => \WP_REST_Server::READABLE, + 'callback' => array( $this, 'get_zones' ), + 'permission_callback' => array( $this, 'check_permission' ), + ), + ) + ); + } + + /** + * Get all shipping zones with their methods + */ + public function get_zones( WP_REST_Request $request ) { + try { + $zones_data = array(); + + // Get all shipping zones + $zones = WC_Shipping_Zones::get_zones(); + + foreach ( $zones as $zone_data ) { + $zone = WC_Shipping_Zones::get_zone( $zone_data['id'] ); + + // Get zone locations (regions) + $locations = $zone->get_zone_locations(); + $regions = array(); + + foreach ( $locations as $location ) { + if ( $location->type === 'country' ) { + $countries = WC()->countries->get_countries(); + $regions[] = $countries[ $location->code ] ?? $location->code; + } elseif ( $location->type === 'state' ) { + $states = WC()->countries->get_states( substr( $location->code, 0, 2 ) ); + $regions[] = $states[ substr( $location->code, 3 ) ] ?? $location->code; + } elseif ( $location->type === 'continent' ) { + $continents = WC()->countries->get_continents(); + $regions[] = $continents[ $location->code ]['name'] ?? $location->code; + } elseif ( $location->type === 'postcode' ) { + $regions[] = 'Postcode: ' . $location->code; + } + } + + // Get shipping methods for this zone + $shipping_methods = $zone->get_shipping_methods( true ); // true = enabled only + $rates = array(); + + foreach ( $shipping_methods as $method ) { + $rate = array( + 'id' => $method->id . ':' . $method->instance_id, + 'instance_id' => $method->instance_id, + 'method_id' => $method->id, + 'name' => $method->get_title(), + 'enabled' => $method->enabled === 'yes', + ); + + // Get cost if available + if ( isset( $method->cost ) && $method->cost !== '' ) { + $rate['price'] = wc_price( $method->cost ); + } elseif ( $method->id === 'free_shipping' ) { + $rate['price'] = __( 'Free', 'woonoow' ); + } else { + $rate['price'] = __( 'Calculated', 'woonoow' ); + } + + // Get method description if available + if ( method_exists( $method, 'get_method_description' ) ) { + $rate['description'] = $method->get_method_description(); + } + + $rates[] = $rate; + } + + $zones_data[] = array( + 'id' => $zone_data['id'], + 'name' => $zone->get_zone_name(), + 'order' => $zone->get_zone_order(), + 'regions' => ! empty( $regions ) ? implode( ', ', $regions ) : __( 'No regions', 'woonoow' ), + 'rates' => $rates, + ); + } + + // Add "Rest of the World" zone (zone 0) + $zone_0 = new \WC_Shipping_Zone( 0 ); + $shipping_methods = $zone_0->get_shipping_methods( true ); + $rates = array(); + + foreach ( $shipping_methods as $method ) { + $rate = array( + 'id' => $method->id . ':' . $method->instance_id, + 'instance_id' => $method->instance_id, + 'method_id' => $method->id, + 'name' => $method->get_title(), + 'enabled' => $method->enabled === 'yes', + ); + + if ( isset( $method->cost ) && $method->cost !== '' ) { + $rate['price'] = wc_price( $method->cost ); + } elseif ( $method->id === 'free_shipping' ) { + $rate['price'] = __( 'Free', 'woonoow' ); + } else { + $rate['price'] = __( 'Calculated', 'woonoow' ); + } + + $rates[] = $rate; + } + + if ( ! empty( $rates ) ) { + $zones_data[] = array( + 'id' => 0, + 'name' => __( 'Rest of the World', 'woonoow' ), + 'order' => 9999, + 'regions' => __( 'Locations not covered by other zones', 'woonoow' ), + 'rates' => $rates, + ); + } + + return new WP_REST_Response( $zones_data, 200 ); + + } catch ( \Exception $e ) { + return new WP_REST_Response( + array( + 'error' => 'fetch_failed', + 'message' => $e->getMessage(), + ), + 500 + ); + } + } + + /** + * Check if user has permission to manage shipping + */ + public function check_permission() { + return current_user_can( 'manage_woocommerce' ); + } +}