Files
WooNooW/SHIPPING_ADDON_RESEARCH.md
dwindown d1b2c6e562 docs: Comprehensive shipping addon integration research
Added SHIPPING_ADDON_RESEARCH.md with findings on:

## Key Insights:
1. **Standard vs Indonesian Plugins**
   - Standard: Simple settings, no custom fields
   - Indonesian: Complex API, custom checkout fields, subdistrict

2. **How Indonesian Plugins Work**
   - Add custom checkout fields (subdistrict)
   - Require origin configuration in wp-admin
   - Make real-time API calls during checkout
   - Calculate rates based on origin-destination pairing

3. **Why They're Complex**
   - 7,000+ subdistricts in Indonesia
   - Each courier has different rates per subdistrict
   - Can't pre-calculate (must use API)
   - Origin + destination required

## WooNooW Strategy:
 DO:
- Display all methods from WooCommerce API
- Show enable/disable toggle
- Show basic settings (title, cost, min_amount)
- Link to WooCommerce for complex config

 DON'T:
- Try to manage custom checkout fields
- Try to calculate rates
- Try to show all plugin settings
- Interfere with plugin functionality

## Next Steps:
1. Detect complex shipping plugins
2. Show different UI for complex methods
3. Add "Configure in WooCommerce" button
4. Hide settings form for complex methods

Result: Simplified UI for standard methods, full power for complex plugins!
2025-11-09 22:26:08 +07:00

9.8 KiB

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

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

// 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

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

// 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

// 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

// 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

// ❌ 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

// ❌ 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

// ❌ DON'T DO THIS
<Input label="Origin Subdistrict ID" />
<Input label="API Key" />
<Input label="Courier Selection" />
  • 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

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

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"

// In the accordion, show:
<AccordionItem>
  <AccordionTrigger>
    🚚 Biteship - JNE REG [On]
    Rp 15,000 (calculated at checkout)
  </AccordionTrigger>
  <AccordionContent>
    <Alert>
      This is a complex shipping method with advanced settings.
      <Button asChild>
        <a href={wcAdminUrl + '/admin.php?page=biteship-settings'}>
          Configure in WooCommerce
        </a>
      </Button>
    </Alert>
    
    {/* Only show basic toggle */}
    <ToggleField 
      label="Enable/Disable"
      value={method.enabled}
      onChange={handleToggle}
    />
  </AccordionContent>
</AccordionItem>

Detection Logic

// 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) ? (
  <ComplexMethodView method={method} />
) : (
  <SimpleMethodView method={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)

  • Display all methods from WooCommerce API
  • Show enable/disable toggle
  • 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