- Add ModuleRegistry for managing built-in modules (newsletter, wishlist, affiliate, subscription, licensing) - Add ModulesController REST API for module enable/disable - Create Modules settings page with category grouping and toggle controls - Integrate module checks across admin-spa and customer-spa - Add useModules hook for both SPAs to check module status - Hide newsletter from footer builder when module disabled - Hide wishlist features when module disabled (product cards, account menu, wishlist page) - Protect wishlist API endpoints with module checks - Auto-update navigation tree when modules toggled - Clean up obsolete documentation files - Add comprehensive documentation: - MODULE_SYSTEM_IMPLEMENTATION.md - MODULE_INTEGRATION_SUMMARY.md - ADDON_MODULE_INTEGRATION.md (proposal) - ADDON_MODULE_DESIGN_DECISIONS.md (design doc) - FEATURE_ROADMAP.md - SHIPPING_INTEGRATION.md Module system provides: - Centralized enable/disable for all features - Automatic navigation updates - Frontend/backend integration - Foundation for addon-module unification
14 KiB
14 KiB
Addon-Module Integration Strategy
Date: December 26, 2025
Status: 🎯 Proposal
Vision
Module Registry as the Single Source of Truth for all extensions - both built-in modules and external addons.
Current State Analysis
What We Have
1. Module System (Just Built)
ModuleRegistry.php- Manages built-in modules- Enable/disable functionality
- Module metadata (label, description, features, icon)
- Categories (Marketing, Customers, Products)
- Settings page UI with toggles
2. Addon System (Existing)
AddonRegistry.php- Manages external addons- SPA route injection
- Hook system integration
- Navigation tree injection
- React component loading
The Opportunity
These two systems should be unified! An addon is just an external module.
Proposed Integration
Concept: Unified Extension Registry
┌─────────────────────────────────────────────────┐
│ Module Registry (Single Source) │
├─────────────────────────────────────────────────┤
│ │
│ Built-in Modules External Addons │
│ ├─ Newsletter ├─ Biteship Shipping │
│ ├─ Wishlist ├─ Subscriptions │
│ ├─ Affiliate ├─ Bookings │
│ ├─ Subscription └─ Custom Reports │
│ └─ Licensing │
│ │
│ All share same interface: │
│ • Enable/disable toggle │
│ • Settings page (optional) │
│ • Icon & metadata │
│ • Feature list │
│ │
└─────────────────────────────────────────────────┘
Implementation Plan
Phase 1: Extend Module Registry for Addons
Backend: ModuleRegistry.php Enhancement
class ModuleRegistry {
/**
* Get all modules (built-in + addons)
*/
public static function get_all_modules() {
$builtin = self::get_builtin_modules();
$addons = self::get_addon_modules();
return array_merge($builtin, $addons);
}
/**
* Get addon modules from AddonRegistry
*/
private static function get_addon_modules() {
$addons = apply_filters('woonoow/addon_registry', []);
$modules = [];
foreach ($addons as $addon_id => $addon) {
$modules[$addon_id] = [
'id' => $addon_id,
'label' => $addon['name'],
'description' => $addon['description'] ?? '',
'category' => $addon['category'] ?? 'addons',
'icon' => $addon['icon'] ?? 'puzzle',
'default_enabled' => false,
'features' => $addon['features'] ?? [],
'is_addon' => true,
'version' => $addon['version'] ?? '1.0.0',
'author' => $addon['author'] ?? '',
'settings_url' => $addon['settings_url'] ?? '', // NEW!
];
}
return $modules;
}
}
Addon Registration Enhancement
// Addon developers register with enhanced metadata
add_filter('woonoow/addon_registry', function($addons) {
$addons['biteship-shipping'] = [
'id' => 'biteship-shipping',
'name' => 'Biteship Shipping',
'description' => 'Indonesia shipping with Biteship API',
'version' => '1.0.0',
'author' => 'WooNooW Team',
'category' => 'shipping', // NEW!
'icon' => 'truck', // NEW!
'features' => [ // NEW!
'Real-time shipping rates',
'Multiple couriers',
'Tracking integration',
],
'settings_url' => '/settings/shipping/biteship', // NEW!
'spa_bundle' => plugin_dir_url(__FILE__) . 'dist/addon.js',
];
return $addons;
});
Phase 2: Module Settings Page with Gear Icon
UI Enhancement: Modules.tsx
{modules.map((module) => (
<div className="flex items-start gap-4 p-4 border rounded-lg">
{/* Icon */}
<div className={`p-3 rounded-lg ${module.enabled ? 'bg-primary/10' : 'bg-muted'}`}>
{getIcon(module.icon)}
</div>
{/* Content */}
<div className="flex-1">
<div className="flex items-center gap-2 mb-1">
<h3 className="font-medium">{module.label}</h3>
{module.enabled && <Badge>Active</Badge>}
{module.is_addon && <Badge variant="outline">Addon</Badge>}
</div>
<p className="text-sm text-muted-foreground mb-2">{module.description}</p>
{/* Features */}
<ul className="space-y-1">
{module.features.map((feature, i) => (
<li key={i} className="text-xs text-muted-foreground">
• {feature}
</li>
))}
</ul>
</div>
{/* Actions */}
<div className="flex items-center gap-2">
{/* Settings Gear Icon - Only if module has settings */}
{module.settings_url && module.enabled && (
<Button
variant="ghost"
size="icon"
onClick={() => navigate(module.settings_url)}
title="Module Settings"
>
<Settings className="h-4 w-4" />
</Button>
)}
{/* Enable/Disable Toggle */}
<Switch
checked={module.enabled}
onCheckedChange={(enabled) => toggleModule.mutate({ moduleId: module.id, enabled })}
/>
</div>
</div>
))}
Phase 3: Dynamic Categories
Support for Addon Categories
// ModuleRegistry.php
public static function get_categories() {
return [
'marketing' => __('Marketing & Sales', 'woonoow'),
'customers' => __('Customer Experience', 'woonoow'),
'products' => __('Products & Inventory', 'woonoow'),
'shipping' => __('Shipping & Fulfillment', 'woonoow'), // NEW!
'payments' => __('Payments & Checkout', 'woonoow'), // NEW!
'analytics' => __('Analytics & Reports', 'woonoow'), // NEW!
'addons' => __('Other Extensions', 'woonoow'), // Fallback
];
}
Frontend: Dynamic Category Rendering
// Modules.tsx
const { data: modulesData } = useQuery({
queryKey: ['modules'],
queryFn: async () => {
const response = await api.get('/modules');
return response as ModulesData;
},
});
// Get unique categories from modules
const categories = Object.keys(modulesData?.grouped || {});
return (
<SettingsLayout title="Module Management">
{categories.map((category) => {
const modules = modulesData.grouped[category] || [];
if (modules.length === 0) return null;
return (
<SettingsCard
key={category}
title={getCategoryLabel(category)}
description={`Manage ${category} modules`}
>
{/* Module cards */}
</SettingsCard>
);
})}
</SettingsLayout>
);
Benefits
1. Unified Management
- ✅ One place to see all extensions (built-in + addons)
- ✅ Consistent enable/disable interface
- ✅ Unified metadata (icon, description, features)
2. Better UX
- ✅ Users don't need to distinguish between "modules" and "addons"
- ✅ Settings gear icon for quick access to module configuration
- ✅ Clear visual indication of what's enabled
3. Developer Experience
- ✅ Addon developers use familiar pattern
- ✅ Automatic integration with module system
- ✅ No extra work to appear in Modules page
4. Extensibility
- ✅ Dynamic categories support any addon type
- ✅ Settings URL allows deep linking to config
- ✅ Version and author info for better management
Example: Biteship Addon Integration
Addon Registration (PHP)
<?php
/**
* Plugin Name: WooNooW Biteship Shipping
* Description: Indonesia shipping with Biteship API
* Version: 1.0.0
* Author: WooNooW Team
*/
add_filter('woonoow/addon_registry', function($addons) {
$addons['biteship-shipping'] = [
'id' => 'biteship-shipping',
'name' => 'Biteship Shipping',
'description' => 'Real-time shipping rates from Indonesian couriers',
'version' => '1.0.0',
'author' => 'WooNooW Team',
'category' => 'shipping',
'icon' => 'truck',
'features' => [
'JNE, J&T, SiCepat, and more',
'Real-time rate calculation',
'Shipment tracking',
'Automatic label printing',
],
'settings_url' => '/settings/shipping/biteship',
'spa_bundle' => plugin_dir_url(__FILE__) . 'dist/addon.js',
];
return $addons;
});
// Register settings route
add_filter('woonoow/spa_routes', function($routes) {
$routes[] = [
'path' => '/settings/shipping/biteship',
'component_url' => plugin_dir_url(__FILE__) . 'dist/Settings.js',
'title' => 'Biteship Settings',
];
return $routes;
});
Result in Modules Page
┌─────────────────────────────────────────────────┐
│ Shipping & Fulfillment │
├─────────────────────────────────────────────────┤
│ │
│ 🚚 Biteship Shipping [⚙️] [Toggle] │
│ Real-time shipping rates from Indonesian... │
│ • JNE, J&T, SiCepat, and more │
│ • Real-time rate calculation │
│ • Shipment tracking │
│ • Automatic label printing │
│ │
│ Version: 1.0.0 | By: WooNooW Team | [Addon] │
│ │
└─────────────────────────────────────────────────┘
Clicking ⚙️ navigates to /settings/shipping/biteship
Migration Path
Step 1: Enhance ModuleRegistry (Backward Compatible)
- Add
get_addon_modules()method - Merge built-in + addon modules
- No breaking changes
Step 2: Update Modules UI
- Add gear icon for settings
- Add "Addon" badge
- Support dynamic categories
Step 3: Document for Addon Developers
- Update ADDON_DEVELOPMENT_GUIDE.md
- Add examples with new metadata
- Show settings page pattern
Step 4: Update Existing Addons (Optional)
- Addons work without changes
- Enhanced metadata is optional
- Settings URL is optional
API Changes
New Module Properties
interface Module {
id: string;
label: string;
description: string;
category: string;
icon: string;
default_enabled: boolean;
features: string[];
enabled: boolean;
// NEW for addons
is_addon?: boolean;
version?: string;
author?: string;
settings_url?: string; // Route to settings page
}
New API Endpoint (Optional)
// GET /woonoow/v1/modules/:module_id/settings
// Returns module-specific settings schema
Settings Page Pattern
Option 1: Dedicated Route (Recommended)
// Addon registers its own settings route
add_filter('woonoow/spa_routes', function($routes) {
$routes[] = [
'path' => '/settings/my-addon',
'component_url' => plugin_dir_url(__FILE__) . 'dist/Settings.js',
];
return $routes;
});
Option 2: Modal/Drawer (Alternative)
// Modules page opens modal with addon settings
<Dialog open={settingsOpen} onOpenChange={setSettingsOpen}>
<DialogContent>
<AddonSettings moduleId={selectedModule} />
</DialogContent>
</Dialog>
Backward Compatibility
Existing Addons Continue to Work
- ✅ No breaking changes
- ✅ Enhanced metadata is optional
- ✅ Addons without metadata still function
- ✅ Gradual migration path
Existing Modules Unaffected
- ✅ Built-in modules work as before
- ✅ No changes to existing module logic
- ✅ Only UI enhancement
Summary
What This Achieves
-
Newsletter Footer Integration ✅
- Newsletter form respects module status
- Hidden from footer builder when disabled
-
Addon-Module Unification 🎯
- Addons appear in Module Registry
- Same enable/disable interface
- Settings gear icon for configuration
-
Better Developer Experience 🎯
- Consistent registration pattern
- Automatic UI integration
- Optional settings page routing
-
Better User Experience 🎯
- One place to manage all extensions
- Clear visual hierarchy
- Quick access to settings
Next Steps
- ✅ Newsletter footer integration (DONE)
- 🎯 Enhance ModuleRegistry for addon support
- 🎯 Add settings URL support to Modules UI
- 🎯 Update documentation
- 🎯 Create example addon with settings
This creates a truly unified extension system where built-in modules and external addons are first-class citizens with the same management interface.