# Shipping Addon Integration Research ## Problem Statement Indonesian shipping plugins (Biteship, Woongkir, etc.) have complex requirements: 1. **Origin address** - configured in wp-admin 2. **Subdistrict field** - custom checkout field 3. **Real-time API calls** - during cart/checkout 4. **Custom field injection** - modify checkout form **Question:** How can WooNooW SPA accommodate these plugins without breaking their functionality? --- ## How WooCommerce Shipping Addons Work ### Standard WooCommerce Pattern ```php class My_Shipping_Method extends WC_Shipping_Method { public function calculate_shipping($package = array()) { // 1. Get settings from $this->get_option() // 2. Calculate rates based on package // 3. Call $this->add_rate($rate) } } ``` **Key Points:** - ✅ Extends `WC_Shipping_Method` - ✅ Uses WooCommerce hooks: `woocommerce_shipping_init`, `woocommerce_shipping_methods` - ✅ Settings stored in `wp_options` table - ✅ Rates calculated during `calculate_shipping()` --- ## Indonesian Shipping Plugins (Biteship, Woongkir, etc.) ### How They Differ from Standard Plugins #### 1. **Custom Checkout Fields** ```php // They add custom fields to checkout add_filter('woocommerce_checkout_fields', function($fields) { $fields['billing']['billing_subdistrict'] = array( 'type' => 'select', 'label' => 'Subdistrict', 'required' => true, 'options' => get_subdistricts() // API call ); return $fields; }); ``` #### 2. **Origin Configuration** - Stored in plugin settings (wp-admin) - Used for API calls to calculate distance/cost - Not exposed in standard WooCommerce shipping settings #### 3. **Real-time API Calls** ```php public function calculate_shipping($package) { // Get origin from plugin settings $origin = get_option('biteship_origin_subdistrict_id'); // Get destination from checkout field $destination = $package['destination']['subdistrict_id']; // Call external API $rates = biteship_api_get_rates($origin, $destination, $weight); foreach ($rates as $rate) { $this->add_rate($rate); } } ``` #### 4. **AJAX Updates** ```javascript // Update shipping when subdistrict changes jQuery('#billing_subdistrict').on('change', function() { jQuery('body').trigger('update_checkout'); }); ``` --- ## Why Indonesian Plugins Are Complex ### 1. **Geographic Complexity** - Indonesia has **34 provinces**, **514 cities**, **7,000+ subdistricts** - Shipping cost varies by subdistrict (not just city) - Standard WooCommerce only has: Country → State → City → Postcode ### 2. **Multiple Couriers** - Each courier has different rates per subdistrict - Real-time API calls required (can't pre-calculate) - Some couriers don't serve all subdistricts ### 3. **Origin-Destination Pairing** - Cost depends on **origin subdistrict** + **destination subdistrict** - Origin must be configured in admin - Destination selected at checkout --- ## How WooNooW SPA Should Handle This ### ✅ **What WooNooW SHOULD Do** #### 1. **Display Methods Correctly** ```typescript // Our current approach is CORRECT const { data: zones } = useQuery({ queryKey: ['shipping-zones'], queryFn: () => api.get('/settings/shipping/zones') }); ``` - ✅ Fetch zones from WooCommerce API - ✅ Display all methods (including Biteship, Woongkir) - ✅ Show enable/disable toggle - ✅ Link to WooCommerce settings for advanced config #### 2. **Expose Basic Settings Only** ```typescript // Show only common settings - Display Name (title) - Cost (if applicable) - Min Amount (if applicable) ``` - ✅ Don't try to show ALL settings - ✅ Complex settings → "Edit in WooCommerce" button #### 3. **Respect Plugin Behavior** - ✅ Don't interfere with checkout field injection - ✅ Don't modify `calculate_shipping()` logic - ✅ Let plugins handle their own API calls --- ### ❌ **What WooNooW SHOULD NOT Do** #### 1. **Don't Try to Manage Custom Fields** ```typescript // ❌ DON'T DO THIS const subdistrictField = { type: 'select', options: await fetchSubdistricts() }; ``` - ❌ Subdistrict fields are managed by shipping plugins - ❌ They inject fields via WooCommerce hooks - ❌ WooNooW SPA doesn't control checkout page #### 2. **Don't Try to Calculate Rates** ```typescript // ❌ DON'T DO THIS const rate = await biteshipAPI.getRates(origin, destination); ``` - ❌ Rate calculation is plugin-specific - ❌ Requires API keys, origin config, etc. - ❌ Should happen during checkout, not in admin #### 3. **Don't Try to Show All Settings** ```typescript // ❌ DON'T DO THIS ``` - ❌ Too complex for simplified UI - ❌ Each plugin has different settings - ❌ Better to link to WooCommerce settings --- ## Comparison: Global vs Indonesian Shipping ### Global Shipping Plugins (ShipStation, EasyPost, etc.) **Characteristics:** - ✅ Standard address fields (Country, State, City, Postcode) - ✅ Pre-calculated rates or simple API calls - ✅ No custom checkout fields needed - ✅ Settings fit in standard WooCommerce UI **Example: Flat Rate** ```php public function calculate_shipping($package) { $rate = array( 'label' => $this->title, 'cost' => $this->get_option('cost') ); $this->add_rate($rate); } ``` ### Indonesian Shipping Plugins (Biteship, Woongkir, etc.) **Characteristics:** - ⚠️ Custom address fields (Province, City, District, **Subdistrict**) - ⚠️ Real-time API calls with origin-destination pairing - ⚠️ Custom checkout field injection - ⚠️ Complex settings (API keys, origin config, courier selection) **Example: Biteship** ```php public function calculate_shipping($package) { $origin_id = get_option('biteship_origin_subdistrict_id'); $dest_id = $package['destination']['subdistrict_id']; $response = wp_remote_post('https://api.biteship.com/v1/rates', array( 'headers' => array('Authorization' => 'Bearer ' . $api_key), 'body' => json_encode(array( 'origin_area_id' => $origin_id, 'destination_area_id' => $dest_id, 'couriers' => $this->get_option('couriers'), 'items' => $package['contents'] )) )); $rates = json_decode($response['body'])->pricing; foreach ($rates as $rate) { $this->add_rate(array( 'label' => $rate->courier_name . ' - ' . $rate->courier_service_name, 'cost' => $rate->price )); } } ``` --- ## Recommendations for WooNooW SPA ### ✅ **Current Approach is CORRECT** Our simplified UI is perfect for: 1. **Standard shipping methods** (Flat Rate, Free Shipping, Local Pickup) 2. **Simple third-party plugins** (basic rate calculators) 3. **Non-tech users** who just want to enable/disable methods ### ✅ **For Complex Plugins (Biteship, Woongkir)** **Strategy: "View-Only + Link to WooCommerce"** ```typescript // In the accordion, show: 🚚 Biteship - JNE REG [On] Rp 15,000 (calculated at checkout) This is a complex shipping method with advanced settings. {/* Only show basic toggle */} ``` ### ✅ **Detection Logic** ```typescript // Detect if method is complex const isComplexMethod = (method: ShippingMethod) => { const complexPlugins = [ 'biteship', 'woongkir', 'anteraja', 'shipper', // Add more as needed ]; return complexPlugins.some(plugin => method.id.includes(plugin) ); }; // Render accordingly {isComplexMethod(method) ? ( ) : ( )} ``` --- ## Testing Strategy ### ✅ **What to Test in WooNooW SPA** 1. **Method Display** - ✅ Biteship methods appear in zone list - ✅ Enable/disable toggle works - ✅ Method name displays correctly 2. **Settings Link** - ✅ "Edit in WooCommerce" button works - ✅ Opens correct settings page 3. **Don't Break Checkout** - ✅ Subdistrict field still appears - ✅ Rates calculate correctly - ✅ AJAX updates work ### ❌ **What NOT to Test in WooNooW SPA** 1. ❌ Rate calculation accuracy 2. ❌ API integration 3. ❌ Subdistrict field functionality 4. ❌ Origin configuration **These are the shipping plugin's responsibility!** --- ## Conclusion ### **WooNooW SPA's Role:** ✅ **Simplified management** for standard shipping methods ✅ **View-only + link** for complex plugins ✅ **Don't interfere** with plugin functionality ### **Shipping Plugin's Role:** ✅ Handle complex settings (origin, API keys, etc.) ✅ Inject custom checkout fields ✅ Calculate rates via API ✅ Manage courier selection ### **Result:** ✅ Non-tech users can enable/disable methods easily ✅ Complex configuration stays in WooCommerce admin ✅ No functionality is lost ✅ Best of both worlds! 🎯 --- ## Implementation Plan ### Phase 1: Detection (Current) - [x] Display all methods from WooCommerce API - [x] Show enable/disable toggle - [x] Show basic settings (title, cost, min_amount) ### Phase 2: Complex Method Handling (Next) - [ ] Detect complex shipping plugins - [ ] Show different UI for complex methods - [ ] Add "Configure in WooCommerce" button - [ ] Hide settings form for complex methods ### Phase 3: Documentation (Final) - [ ] Add help text explaining complex methods - [ ] Link to plugin documentation - [ ] Add troubleshooting guide --- **Last Updated:** Nov 9, 2025 **Status:** Research Complete ✅