feat: Implement centralized module management system
- 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
This commit is contained in:
476
ADDON_MODULE_INTEGRATION.md
Normal file
476
ADDON_MODULE_INTEGRATION.md
Normal file
@@ -0,0 +1,476 @@
|
||||
# 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
|
||||
|
||||
```php
|
||||
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
|
||||
|
||||
```php
|
||||
// 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
|
||||
|
||||
```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
|
||||
|
||||
```php
|
||||
// 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
|
||||
|
||||
```tsx
|
||||
// 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
|
||||
<?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
|
||||
|
||||
```typescript
|
||||
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)
|
||||
|
||||
```php
|
||||
// GET /woonoow/v1/modules/:module_id/settings
|
||||
// Returns module-specific settings schema
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Settings Page Pattern
|
||||
|
||||
### Option 1: Dedicated Route (Recommended)
|
||||
|
||||
```php
|
||||
// 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)
|
||||
|
||||
```tsx
|
||||
// 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
|
||||
|
||||
1. **Newsletter Footer Integration** ✅
|
||||
- Newsletter form respects module status
|
||||
- Hidden from footer builder when disabled
|
||||
|
||||
2. **Addon-Module Unification** 🎯
|
||||
- Addons appear in Module Registry
|
||||
- Same enable/disable interface
|
||||
- Settings gear icon for configuration
|
||||
|
||||
3. **Better Developer Experience** 🎯
|
||||
- Consistent registration pattern
|
||||
- Automatic UI integration
|
||||
- Optional settings page routing
|
||||
|
||||
4. **Better User Experience** 🎯
|
||||
- One place to manage all extensions
|
||||
- Clear visual hierarchy
|
||||
- Quick access to settings
|
||||
|
||||
### Next Steps
|
||||
|
||||
1. ✅ Newsletter footer integration (DONE)
|
||||
2. 🎯 Enhance ModuleRegistry for addon support
|
||||
3. 🎯 Add settings URL support to Modules UI
|
||||
4. 🎯 Update documentation
|
||||
5. 🎯 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.**
|
||||
Reference in New Issue
Block a user