Files
WooNooW/ADDON_MODULE_INTEGRATION.md
Dwindi Ramadhana 07020bc0dd 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
2025-12-26 19:19:49 +07:00

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

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

  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.