namespace, '/' . $this->rest_base . '/zones', array( array( 'methods' => \WP_REST_Server::READABLE, 'callback' => array( $this, 'get_zones' ), 'permission_callback' => array( $this, 'check_permission' ), ), ) ); // Toggle shipping method register_rest_route( $this->namespace, '/' . $this->rest_base . '/zones/(?P\d+)/methods/(?P\d+)/toggle', array( array( 'methods' => \WP_REST_Server::CREATABLE, 'callback' => array( $this, 'toggle_method' ), 'permission_callback' => array( $this, 'check_permission' ), 'args' => array( 'zone_id' => array( 'required' => true, 'type' => 'integer', ), 'instance_id' => array( 'required' => true, 'type' => 'integer', ), 'enabled' => array( 'required' => true, 'type' => 'boolean', ), ), ), ) ); } /** * 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 (false = get all, not just enabled) $shipping_methods = $zone->get_shipping_methods( false ); $rates = array(); foreach ( $shipping_methods as $method ) { // Get fresh settings from database $method->init_instance_settings(); $is_enabled = isset( $method->instance_settings['enabled'] ) && $method->instance_settings['enabled'] === 'yes'; $rate = array( 'id' => $method->id . ':' . $method->instance_id, 'instance_id' => $method->instance_id, 'method_id' => $method->id, 'name' => $method->get_title(), 'enabled' => $is_enabled, ); // 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( false ); $rates = array(); foreach ( $shipping_methods as $method ) { // Get fresh settings from database $method->init_instance_settings(); $is_enabled = isset( $method->instance_settings['enabled'] ) && $method->instance_settings['enabled'] === 'yes'; $rate = array( 'id' => $method->id . ':' . $method->instance_id, 'instance_id' => $method->instance_id, 'method_id' => $method->id, 'name' => $method->get_title(), 'enabled' => $is_enabled, ); 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 ); } } /** * Toggle shipping method enabled/disabled */ public function toggle_method( WP_REST_Request $request ) { try { $zone_id = $request->get_param( 'zone_id' ); $instance_id = $request->get_param( 'instance_id' ); $enabled = $request->get_param( 'enabled' ); // Convert to boolean (handles both bool and string "true"/"false") $enabled = filter_var( $enabled, FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE ); if ( $enabled === null ) { return new WP_REST_Response( array( 'error' => 'invalid_enabled_value', 'message' => __( 'The "enabled" parameter must be a boolean', 'woonoow' ), ), 400 ); } // Get the zone $zone = \WC_Shipping_Zones::get_zone( $zone_id ); if ( ! $zone ) { return new WP_REST_Response( array( 'error' => 'zone_not_found', 'message' => __( 'Shipping zone not found', 'woonoow' ), ), 404 ); } // CRITICAL: Get ALL shipping methods (both enabled and disabled) $shipping_methods = $zone->get_shipping_methods( false ); $method_found = false; foreach ( $shipping_methods as $method ) { if ( $method->instance_id == $instance_id ) { $method_found = true; // Debug logging error_log( sprintf( '[WooNooW] Toggling shipping method %s (instance %d) to %s', $method->id, $instance_id, $enabled ? 'enabled' : 'disabled' ) ); // Get current settings $method->init_instance_settings(); $current_settings = $method->instance_settings; // Update enabled status $method->instance_settings['enabled'] = $enabled ? 'yes' : 'no'; // Debug: Log settings change error_log( sprintf( '[WooNooW] Current enabled: %s, New enabled: %s', isset( $current_settings['enabled'] ) ? $current_settings['enabled'] : 'not set', $method->instance_settings['enabled'] ) ); // Save to database $option_key = $method->get_instance_option_key(); $saved = update_option( $option_key, $method->instance_settings, 'yes' ); error_log( sprintf( '[WooNooW] update_option(%s) returned: %s', $option_key, $saved ? 'true' : 'false' ) ); // Fire action hook for other plugins/code do_action( 'woocommerce_shipping_zone_method_status_toggled', $instance_id, $method->id, $zone_id, $enabled ); break; } } if ( ! $method_found ) { return new WP_REST_Response( array( 'error' => 'method_not_found', 'message' => __( 'Shipping method not found', 'woonoow' ), ), 404 ); } // Clear shipping cache \WC_Cache_Helper::get_transient_version( 'shipping', true ); wp_cache_flush(); return new WP_REST_Response( array( 'success' => true, 'message' => $enabled ? __( 'Shipping method enabled', 'woonoow' ) : __( 'Shipping method disabled', 'woonoow' ), ), 200 ); } catch ( \Exception $e ) { error_log( sprintf( '[WooNooW] Toggle exception: %s', $e->getMessage() ) ); return new WP_REST_Response( array( 'error' => 'toggle_failed', 'message' => $e->getMessage(), ), 500 ); } } /** * Check if user has permission to manage shipping */ public function check_permission() { return current_user_can( 'manage_woocommerce' ); } }