feat: Implement Phase 2, 3, 4 - Module Settings System with Schema Forms and Addon API
Phase 2: Schema-Based Form System
- Add ModuleSettingsController with GET/POST/schema endpoints
- Create SchemaField component supporting 8 field types (text, textarea, email, url, number, toggle, checkbox, select)
- Create SchemaForm component for automatic form generation from schema
- Add ModuleSettings page with dynamic routing (/settings/modules/:moduleId)
- Add useModuleSettings React hook for settings management
- Implement NewsletterSettings as example with 8 configurable fields
- Add has_settings flag to module registry
- Settings stored as woonoow_module_{module_id}_settings
Phase 3: Advanced Features
- Create windowAPI.ts exposing React, hooks, components, icons, utils to addons via window.WooNooW
- Add DynamicComponentLoader for loading external React components
- Create TypeScript definitions (woonoow-addon.d.ts) for addon developers
- Initialize Window API in App.tsx on mount
- Enable custom React components for addon settings pages
Phase 4: Production Polish & Example
- Create complete Biteship addon example demonstrating both approaches:
* Schema-based settings (no build required)
* Custom React component (with build)
- Add comprehensive README with installation and testing guide
- Include package.json with esbuild configuration
- Demonstrate window.WooNooW API usage in custom component
Bug Fixes:
- Fix footer newsletter form visibility (remove redundant module check)
- Fix footer contact_data and social_links not saving (parameter name mismatch: snake_case vs camelCase)
- Fix useModules hook returning undefined (remove .data wrapper, add fallback)
- Add optional chaining to footer settings rendering
- Fix TypeScript errors in woonoow-addon.d.ts (use any for external types)
Files Added (15):
- includes/Api/ModuleSettingsController.php
- includes/Modules/NewsletterSettings.php
- admin-spa/src/components/forms/SchemaField.tsx
- admin-spa/src/components/forms/SchemaForm.tsx
- admin-spa/src/routes/Settings/ModuleSettings.tsx
- admin-spa/src/hooks/useModuleSettings.ts
- admin-spa/src/lib/windowAPI.ts
- admin-spa/src/components/DynamicComponentLoader.tsx
- types/woonoow-addon.d.ts
- examples/biteship-addon/biteship-addon.php
- examples/biteship-addon/src/Settings.jsx
- examples/biteship-addon/package.json
- examples/biteship-addon/README.md
- PHASE_2_3_4_SUMMARY.md
Files Modified (11):
- admin-spa/src/App.tsx
- admin-spa/src/hooks/useModules.ts
- admin-spa/src/routes/Appearance/Footer.tsx
- admin-spa/src/routes/Settings/Modules.tsx
- customer-spa/src/hooks/useModules.ts
- customer-spa/src/layouts/BaseLayout.tsx
- customer-spa/src/components/NewsletterForm.tsx
- includes/Api/Routes.php
- includes/Api/ModulesController.php
- includes/Core/ModuleRegistry.php
- woonoow.php
API Endpoints Added:
- GET /woonoow/v1/modules/{module_id}/settings
- POST /woonoow/v1/modules/{module_id}/settings
- GET /woonoow/v1/modules/{module_id}/schema
For Addon Developers:
- Schema-based: Define settings via woonoow/module_settings_schema filter
- Custom React: Build component using window.WooNooW API, externalize react/react-dom
- Both approaches use same storage and retrieval methods
- TypeScript definitions provided for type safety
- Complete working example (Biteship) included
This commit is contained in:
200
admin-spa/src/lib/windowAPI.ts
Normal file
200
admin-spa/src/lib/windowAPI.ts
Normal file
@@ -0,0 +1,200 @@
|
||||
/**
|
||||
* WooNooW Window API
|
||||
*
|
||||
* Exposes React, hooks, components, and utilities to addon developers
|
||||
* via window.WooNooW object
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom/client';
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { toast } from 'sonner';
|
||||
|
||||
// UI Components
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { Textarea } from '@/components/ui/textarea';
|
||||
import { Switch } from '@/components/ui/switch';
|
||||
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
||||
import { Checkbox } from '@/components/ui/checkbox';
|
||||
import { Badge } from '@/components/ui/badge';
|
||||
import { Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@/components/ui/card';
|
||||
|
||||
// Settings Components
|
||||
import { SettingsLayout } from '@/routes/Settings/components/SettingsLayout';
|
||||
import { SettingsCard } from '@/routes/Settings/components/SettingsCard';
|
||||
import { SettingsSection } from '@/routes/Settings/components/SettingsSection';
|
||||
|
||||
// Form Components
|
||||
import { SchemaForm } from '@/components/forms/SchemaForm';
|
||||
import { SchemaField } from '@/components/forms/SchemaField';
|
||||
|
||||
// Hooks
|
||||
import { useModules } from '@/hooks/useModules';
|
||||
import { useModuleSettings } from '@/hooks/useModuleSettings';
|
||||
|
||||
// Utils
|
||||
import { api } from '@/lib/api';
|
||||
import { __ } from '@/lib/i18n';
|
||||
|
||||
// Icons (commonly used)
|
||||
import {
|
||||
Settings,
|
||||
Save,
|
||||
Trash2,
|
||||
Edit,
|
||||
Plus,
|
||||
X,
|
||||
Check,
|
||||
AlertCircle,
|
||||
Info,
|
||||
Loader2,
|
||||
ChevronDown,
|
||||
ChevronUp,
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
} from 'lucide-react';
|
||||
|
||||
/**
|
||||
* WooNooW Window API Interface
|
||||
*/
|
||||
export interface WooNooWAPI {
|
||||
React: typeof React;
|
||||
ReactDOM: typeof ReactDOM;
|
||||
|
||||
hooks: {
|
||||
useQuery: typeof useQuery;
|
||||
useMutation: typeof useMutation;
|
||||
useQueryClient: typeof useQueryClient;
|
||||
useModules: typeof useModules;
|
||||
useModuleSettings: typeof useModuleSettings;
|
||||
};
|
||||
|
||||
components: {
|
||||
// Basic UI
|
||||
Button: typeof Button;
|
||||
Input: typeof Input;
|
||||
Label: typeof Label;
|
||||
Textarea: typeof Textarea;
|
||||
Switch: typeof Switch;
|
||||
Select: typeof Select;
|
||||
SelectContent: typeof SelectContent;
|
||||
SelectItem: typeof SelectItem;
|
||||
SelectTrigger: typeof SelectTrigger;
|
||||
SelectValue: typeof SelectValue;
|
||||
Checkbox: typeof Checkbox;
|
||||
Badge: typeof Badge;
|
||||
Card: typeof Card;
|
||||
CardContent: typeof CardContent;
|
||||
CardDescription: typeof CardDescription;
|
||||
CardFooter: typeof CardFooter;
|
||||
CardHeader: typeof CardHeader;
|
||||
CardTitle: typeof CardTitle;
|
||||
|
||||
// Settings Components
|
||||
SettingsLayout: typeof SettingsLayout;
|
||||
SettingsCard: typeof SettingsCard;
|
||||
SettingsSection: typeof SettingsSection;
|
||||
|
||||
// Form Components
|
||||
SchemaForm: typeof SchemaForm;
|
||||
SchemaField: typeof SchemaField;
|
||||
};
|
||||
|
||||
icons: {
|
||||
Settings: typeof Settings;
|
||||
Save: typeof Save;
|
||||
Trash2: typeof Trash2;
|
||||
Edit: typeof Edit;
|
||||
Plus: typeof Plus;
|
||||
X: typeof X;
|
||||
Check: typeof Check;
|
||||
AlertCircle: typeof AlertCircle;
|
||||
Info: typeof Info;
|
||||
Loader2: typeof Loader2;
|
||||
ChevronDown: typeof ChevronDown;
|
||||
ChevronUp: typeof ChevronUp;
|
||||
ChevronLeft: typeof ChevronLeft;
|
||||
ChevronRight: typeof ChevronRight;
|
||||
};
|
||||
|
||||
utils: {
|
||||
api: typeof api;
|
||||
toast: typeof toast;
|
||||
__: typeof __;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize Window API
|
||||
* Exposes WooNooW API to window object for addon developers
|
||||
*/
|
||||
export function initializeWindowAPI() {
|
||||
const windowAPI: WooNooWAPI = {
|
||||
React,
|
||||
ReactDOM,
|
||||
|
||||
hooks: {
|
||||
useQuery,
|
||||
useMutation,
|
||||
useQueryClient,
|
||||
useModules,
|
||||
useModuleSettings,
|
||||
},
|
||||
|
||||
components: {
|
||||
Button,
|
||||
Input,
|
||||
Label,
|
||||
Textarea,
|
||||
Switch,
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
Checkbox,
|
||||
Badge,
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
SettingsLayout,
|
||||
SettingsCard,
|
||||
SettingsSection,
|
||||
SchemaForm,
|
||||
SchemaField,
|
||||
},
|
||||
|
||||
icons: {
|
||||
Settings,
|
||||
Save,
|
||||
Trash2,
|
||||
Edit,
|
||||
Plus,
|
||||
X,
|
||||
Check,
|
||||
AlertCircle,
|
||||
Info,
|
||||
Loader2,
|
||||
ChevronDown,
|
||||
ChevronUp,
|
||||
ChevronLeft,
|
||||
ChevronRight,
|
||||
},
|
||||
|
||||
utils: {
|
||||
api,
|
||||
toast,
|
||||
__,
|
||||
},
|
||||
};
|
||||
|
||||
// Expose to window
|
||||
(window as any).WooNooW = windowAPI;
|
||||
|
||||
console.log('✅ WooNooW API initialized for addon developers');
|
||||
}
|
||||
Reference in New Issue
Block a user