Newsletter Fix: - Move all hooks (useQuery, useMutation) before conditional returns - Add 'enabled' option to useQuery to control when it fetches - Fixes React error #310: useEffect called conditionally - Newsletter page now loads without errors at /marketing/newsletter Wishlist Module Refactoring: - Create WishlistSettings.php with 8 configurable settings: * Enable guest wishlists * Wishlist page selector * Show in header toggle * Enable sharing * Back in stock notifications * Max items per wishlist * Multiple wishlists support * Show add to cart button - Add has_settings flag to wishlist module in ModuleRegistry - Initialize WishlistSettings in woonoow.php - Update customer-spa BaseLayout to use isEnabled('wishlist') check - Wishlist page already has module check (no changes needed) Files Added (1): - includes/Modules/WishlistSettings.php Files Modified (5): - admin-spa/src/routes/Marketing/Newsletter.tsx - includes/Core/ModuleRegistry.php - woonoow.php - customer-spa/src/layouts/BaseLayout.tsx - admin-spa/dist/app.js (rebuilt) Both newsletter and wishlist now follow the same module pattern: - Settings via schema (no code required) - Module enable/disable controls feature visibility - Settings page at /settings/modules/{module_id} - Consistent user experience
Biteship Shipping Addon - Example
This is a complete example of a WooNooW addon that integrates with the module system.
Features Demonstrated
1. Module Registration
- Registers as a shipping module with icon, category, and features
- Appears in Settings > Modules automatically
- Shows gear icon for settings access
2. Two Settings Approaches
Option A: Schema-Based (No React Needed)
Uncomment the schema registration in biteship-addon.php and set settings_component to null.
Benefits:
- No build process required
- Automatic form generation
- Built-in validation
- Perfect for simple settings
Option B: Custom React Component (Current)
Uses src/Settings.jsx with WooNooW's exposed React API.
Benefits:
- Full UI control
- Custom validation logic
- Advanced interactions (like "Test Connection" button)
- Better for complex settings
3. Settings Persistence
Both approaches use the same storage:
- Stored in:
woonoow_module_biteship-shipping_settings - Accessed via:
get_option('woonoow_module_biteship-shipping_settings') - React hook:
useModuleSettings('biteship-shipping')
4. Module Integration
- Hooks into
woonoow/shipping/calculate_ratesfilter - Checks if module is enabled before running
- Reacts to settings changes via action hook
Installation
Development Mode (No Build)
- Copy this folder to
wp-content/plugins/ - Activate the plugin
- Go to Settings > Modules
- Enable "Biteship Shipping"
- Click gear icon to configure
Production Mode (With Build)
cd biteship-addon
npm install
npm run build
This compiles src/Settings.jsx to dist/Settings.js.
File Structure
biteship-addon/
├── biteship-addon.php # Main plugin file
├── src/
│ └── Settings.jsx # Custom React settings component
├── dist/
│ └── Settings.js # Compiled component (after build)
├── package.json # Build configuration
└── README.md # This file
Using WooNooW API
The custom settings component uses window.WooNooW API:
const { React, hooks, components, icons, utils } = window.WooNooW;
// Hooks
const { useModuleSettings } = hooks;
const { settings, updateSettings } = useModuleSettings('biteship-shipping');
// Components
const { SettingsLayout, SettingsCard, Button, Input } = components;
// Icons
const { Save, Settings } = icons;
// Utils
const { toast, api } = utils;
Build Configuration
{
"scripts": {
"build": "esbuild src/Settings.jsx --bundle --outfile=dist/Settings.js --format=iife --external:react --external:react-dom"
}
}
Important: Externalize React and React-DOM since WooNooW provides them!
API Integration
The example shows placeholder shipping rates. In production:
- Call Biteship API in
woonoow/shipping/calculate_ratesfilter - Use settings from
get_option('woonoow_module_biteship-shipping_settings') - Return formatted rates array
Settings Schema Reference
'field_name' => [
'type' => 'text|textarea|email|url|number|toggle|checkbox|select',
'label' => 'Field Label',
'description' => 'Help text',
'placeholder' => 'Placeholder text',
'required' => true|false,
'default' => 'default value',
'options' => ['key' => 'Label'], // For select fields
'min' => 0, // For number fields
'max' => 100, // For number fields
]
Module Registration Reference
add_filter('woonoow/addon_registry', function($addons) {
$addons['your-addon-id'] = [
'id' => 'your-addon-id',
'name' => 'Your Addon Name',
'description' => 'Short description',
'version' => '1.0.0',
'author' => 'Your Name',
'category' => 'shipping|payments|marketing|customers|products|analytics|other',
'icon' => 'truck|credit-card|mail|users|package|bar-chart-3|puzzle',
'features' => ['Feature 1', 'Feature 2'],
'has_settings' => true,
'settings_component' => plugin_dir_url(__FILE__) . 'dist/Settings.js', // Or null for schema
];
return $addons;
});
Testing
- Enable the module in Settings > Modules
- Click gear icon
- Enter a test API key (format:
biteship_xxxxx) - Click "Test Connection" button
- Save settings
- Check that settings persist on page refresh
Next Steps
- Implement real Biteship API integration
- Add courier selection UI
- Add tracking number display
- Add shipping label generation
- Add webhook handling for status updates
Support
For questions about WooNooW addon development:
- Read:
ADDON_DEVELOPMENT_GUIDE.md - Read:
ADDON_MODULE_DESIGN_DECISIONS.md - Check:
types/woonoow-addon.d.tsfor TypeScript definitions