refactor: Migrate documentation content, rebuild UI components, and update core architecture.
This commit is contained in:
79
docs/developer/addons/bridge-pattern.mdx
Normal file
79
docs/developer/addons/bridge-pattern.mdx
Normal file
@@ -0,0 +1,79 @@
|
||||
---
|
||||
title: Bridge Pattern
|
||||
description: Integrating third-party plugins with WooNooW
|
||||
date: 2024-01-31
|
||||
---
|
||||
|
||||
|
||||
|
||||
## Philosophy
|
||||
|
||||
**WooNooW Core = Zero Addon Dependencies**
|
||||
|
||||
We don't integrate specific plugins into WooNooW core. Instead, we provide:
|
||||
1. **Hook system** for addons to extend functionality
|
||||
2. **Bridge snippets** for compatibility with existing plugins
|
||||
3. **Addon development guide** for building proper WooNooW addons
|
||||
|
||||
---
|
||||
|
||||
## The Problem
|
||||
|
||||
Example: **Rajaongkir** (Indonesian Shipping Plugin).
|
||||
It removes standard fields and adds custom dropdowns, storing data in WooCommerce sessions.
|
||||
It doesn't work with WooNooW OrderForm out of the box because the OrderForm uses standard fields and API-based validation.
|
||||
|
||||
---
|
||||
|
||||
## Solution: Bridge Snippet
|
||||
|
||||
### Option A: Standalone Bridge Plugin
|
||||
|
||||
Create a tiny bridge plugin that makes the third-party plugin work with WooNooW.
|
||||
|
||||
```php
|
||||
/**
|
||||
* Plugin Name: WooNooW Rajaongkir Bridge
|
||||
* Description: Makes Rajaongkir plugin work with WooNooW OrderForm
|
||||
* Version: 1.0.0
|
||||
*/
|
||||
|
||||
// Hook into WooNooW's shipping calculation
|
||||
add_filter('woonoow_before_shipping_calculate', function($shipping_data) {
|
||||
if ($shipping_data['country'] === 'ID' && !empty($shipping_data['city'])) {
|
||||
// Search API and set session data
|
||||
$api = Cekongkir_API::get_instance();
|
||||
$results = $api->search_destination_api($shipping_data['city']);
|
||||
|
||||
if (!empty($results[0])) {
|
||||
WC()->session->set('selected_destination_id', $results[0]['id']);
|
||||
}
|
||||
}
|
||||
return $shipping_data;
|
||||
});
|
||||
```
|
||||
|
||||
### Option B: Frontend Injection
|
||||
|
||||
Inject script to handle UI changes.
|
||||
|
||||
```typescript
|
||||
import { addonLoader, addFilter } from '@woonoow/hooks';
|
||||
|
||||
addonLoader.register({
|
||||
id: 'rajaongkir-bridge',
|
||||
init: () => {
|
||||
addFilter('woonoow_order_form_after_shipping', (content, formData, setFormData) => {
|
||||
if (formData.shipping?.country !== 'ID') return content;
|
||||
return (
|
||||
<>
|
||||
{content}
|
||||
<div className="custom-field">
|
||||
{/* Custom Destination Select */}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
```
|
||||
311
docs/developer/addons/custom-channels.mdx
Normal file
311
docs/developer/addons/custom-channels.mdx
Normal file
@@ -0,0 +1,311 @@
|
||||
---
|
||||
title: Custom Notification Channels
|
||||
description: Learn how to add custom notification channels like WhatsApp, SMS, or Telegram to WooNooW
|
||||
---
|
||||
|
||||
|
||||
|
||||
WooNooW supports custom notification channels through a pluggable architecture. You can extend the notification system to send messages via WhatsApp, SMS, Telegram, or any other service.
|
||||
|
||||
## Architecture Overview
|
||||
|
||||
The multi-channel notification system consists of three core components:
|
||||
|
||||
1. **`ChannelInterface`** - Contract that all channels must implement
|
||||
2. **`ChannelRegistry`** - Central registry for managing channels
|
||||
3. **`NotificationManager`** - Sends notifications through registered channels
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A[NotificationManager] --> B[ChannelRegistry]
|
||||
B --> C[Email Channel]
|
||||
B --> D[WhatsApp Channel]
|
||||
B --> E[SMS Channel]
|
||||
B --> F[Custom Channel]
|
||||
```
|
||||
|
||||
## Creating a Custom Channel
|
||||
|
||||
### Step 1: Implement ChannelInterface
|
||||
|
||||
Create a class that implements `WooNooW\Core\Notifications\Channels\ChannelInterface`:
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace MyPlugin\Channels;
|
||||
|
||||
use WooNooW\Core\Notifications\Channels\ChannelInterface;
|
||||
|
||||
class WhatsAppChannel implements ChannelInterface {
|
||||
|
||||
public function get_id() {
|
||||
return 'whatsapp';
|
||||
}
|
||||
|
||||
public function get_label() {
|
||||
return __('WhatsApp', 'my-plugin');
|
||||
}
|
||||
|
||||
public function is_configured() {
|
||||
$api_key = get_option('my_whatsapp_api_key');
|
||||
return !empty($api_key);
|
||||
}
|
||||
|
||||
public function send($event_id, $recipient, $data) {
|
||||
// Your sending logic here
|
||||
return [
|
||||
'success' => true,
|
||||
'message' => 'Sent successfully'
|
||||
];
|
||||
}
|
||||
|
||||
public function get_config_fields() {
|
||||
return [
|
||||
[
|
||||
'id' => 'my_whatsapp_api_key',
|
||||
'label' => 'API Key',
|
||||
'type' => 'text',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: Register Your Channel
|
||||
|
||||
Register your channel with the `ChannelRegistry` during plugin initialization:
|
||||
|
||||
```php
|
||||
use WooNooW\Core\Notifications\ChannelRegistry;
|
||||
use MyPlugin\Channels\WhatsAppChannel;
|
||||
|
||||
add_action('init', function() {
|
||||
$channel = new WhatsAppChannel();
|
||||
ChannelRegistry::register($channel);
|
||||
});
|
||||
```
|
||||
|
||||
### Step 3: Enable in Settings
|
||||
|
||||
Once registered, your channel will be available in the notification settings UI, where users can configure which events should use WhatsApp.
|
||||
|
||||
## Interface Reference
|
||||
|
||||
### get_id()
|
||||
|
||||
Returns a unique identifier for your channel.
|
||||
|
||||
```php
|
||||
public function get_id(): string
|
||||
```
|
||||
|
||||
**Example:**
|
||||
```php
|
||||
public function get_id() {
|
||||
return 'whatsapp'; // or 'sms', 'telegram', etc.
|
||||
}
|
||||
```
|
||||
|
||||
### get_label()
|
||||
|
||||
Returns a human-readable label for the admin UI.
|
||||
|
||||
```php
|
||||
public function get_label(): string
|
||||
```
|
||||
|
||||
**Example:**
|
||||
```php
|
||||
public function get_label() {
|
||||
return __('WhatsApp Business', 'my-plugin');
|
||||
}
|
||||
```
|
||||
|
||||
### is_configured()
|
||||
|
||||
Checks if the channel has all required configuration (API keys, credentials, etc.).
|
||||
|
||||
```php
|
||||
public function is_configured(): bool
|
||||
```
|
||||
|
||||
**Example:**
|
||||
```php
|
||||
public function is_configured() {
|
||||
$api_key = get_option('my_whatsapp_api_key');
|
||||
$phone = get_option('my_whatsapp_phone');
|
||||
return !empty($api_key) && !empty($phone);
|
||||
}
|
||||
```
|
||||
|
||||
### send()
|
||||
|
||||
Sends a notification through this channel.
|
||||
|
||||
```php
|
||||
public function send(string $event_id, string $recipient, array $data): bool|array
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
- `$event_id` - Event identifier (e.g., `'order_completed'`, `'newsletter_confirm'`)
|
||||
- `$recipient` - Recipient type (`'customer'` or `'staff'`)
|
||||
- `$data` - Context data including order, user, custom variables
|
||||
|
||||
**Returns:**
|
||||
- `bool` - Simple success/failure
|
||||
- `array` - Detailed result with `success` and `message` keys
|
||||
|
||||
**Example:**
|
||||
```php
|
||||
public function send($event_id, $recipient, $data) {
|
||||
$phone = $this->get_recipient_phone($recipient, $data);
|
||||
$message = $this->build_message($event_id, $data);
|
||||
|
||||
$response = wp_remote_post('https://api.provider.com/send', [
|
||||
'body' => [
|
||||
'to' => $phone,
|
||||
'message' => $message,
|
||||
'api_key' => get_option('my_api_key'),
|
||||
],
|
||||
]);
|
||||
|
||||
if (is_wp_error($response)) {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => $response->get_error_message(),
|
||||
];
|
||||
}
|
||||
|
||||
return ['success' => true];
|
||||
}
|
||||
```
|
||||
|
||||
### get_config_fields()
|
||||
|
||||
Returns configuration fields for the admin settings UI (optional).
|
||||
|
||||
```php
|
||||
public function get_config_fields(): array
|
||||
```
|
||||
|
||||
**Field Structure:**
|
||||
```php
|
||||
[
|
||||
'id' => 'option_name',
|
||||
'label' => 'Field Label',
|
||||
'type' => 'text|select|textarea',
|
||||
'description' => 'Help text',
|
||||
'options' => [], // For select fields
|
||||
'default' => 'value',
|
||||
]
|
||||
```
|
||||
|
||||
## Complete Example: WhatsApp Channel
|
||||
|
||||
See the reference implementation:
|
||||
[WhatsAppChannel.example.php](file:///Users/dwindown/Local%20Sites/woonoow/app/public/wp-content/plugins/woonoow/includes/Core/Notifications/Channels/WhatsAppChannel.example.php)
|
||||
|
||||
This example includes:
|
||||
- ✅ Twilio API integration
|
||||
- ✅ Phone number extraction from orders/users
|
||||
- ✅ Message templates for common events
|
||||
- ✅ Configuration fields for admin settings
|
||||
|
||||
## Message Customization
|
||||
|
||||
Use filters to customize messages for specific events:
|
||||
|
||||
```php
|
||||
add_filter('woonoow_whatsapp_message_order_completed', function($message, $data) {
|
||||
if (isset($data['order'])) {
|
||||
$order = $data['order'];
|
||||
return sprintf(
|
||||
"🎉 Order #%s confirmed! Track here: %s",
|
||||
$order->get_order_number(),
|
||||
$order->get_view_order_url()
|
||||
);
|
||||
}
|
||||
return $message;
|
||||
}, 10, 2);
|
||||
```
|
||||
|
||||
## Available Events
|
||||
|
||||
Your channel can handle any registered notification event:
|
||||
|
||||
| Event | Recipient | Data Available |
|
||||
|-------|-----------|----------------|
|
||||
| `order_completed` | customer | `order`, `user_id` |
|
||||
| `order_cancelled` | customer | `order`, `user_id` |
|
||||
| `newsletter_confirm` | customer | `email`, `confirmation_url` |
|
||||
| `newsletter_welcome` | customer | `email`, `user_id` |
|
||||
| `subscription_expiring` | customer | `subscription`, `user_id` |
|
||||
|
||||
See [Event Registry](/hooks/notifications#event-registry) for the complete list.
|
||||
|
||||
## Testing Your Channel
|
||||
|
||||
```php
|
||||
// Manual test
|
||||
use WooNooW\Core\Notifications\NotificationManager;
|
||||
|
||||
NotificationManager::send('order_completed', 'whatsapp', [
|
||||
'order' => wc_get_order(123),
|
||||
'user_id' => 1,
|
||||
]);
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Validate Configuration**: Always check `is_configured()` before attempting to send
|
||||
2. **Handle Errors Gracefully**: Return detailed error messages for debugging
|
||||
3. **Log Send Attempts**: Use `do_action()` for tracking/analytics
|
||||
4. **Support Filtering**: Allow message customization via filters
|
||||
5. **Rate Limiting**: Consider implementing rate limiting for API calls
|
||||
|
||||
## Hooks
|
||||
|
||||
### Registration Hook
|
||||
```php
|
||||
// Register channels during init
|
||||
add_action('init', function() {
|
||||
ChannelRegistry::register(new MyChannel());
|
||||
});
|
||||
```
|
||||
|
||||
### Custom Hooks in Your Channel
|
||||
```php
|
||||
// Allow logging/tracking
|
||||
do_action('my_channel_sent', $event_id, $recipient, $result);
|
||||
|
||||
// Allow message customization
|
||||
$message = apply_filters(
|
||||
"my_channel_message_{$event_id}",
|
||||
$default_message,
|
||||
$data
|
||||
);
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**Channel not appearing in settings?**
|
||||
- Ensure `ChannelRegistry::register()` is called during `init`
|
||||
- Check that `get_id()` returns a unique string
|
||||
- Verify `is_configured()` returns `true`
|
||||
|
||||
**Messages not sending?**
|
||||
- Check notification settings: Marketing > Notifications
|
||||
- Verify the event has your channel enabled
|
||||
- Enable debug mode and check logs
|
||||
- Test `is_configured()` returns true
|
||||
|
||||
**API errors?**
|
||||
- Validate API credentials in settings
|
||||
- Check API provider status/quotas
|
||||
- Review error logs for API responses
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Notification System](/core-concepts/notifications)
|
||||
- [Event Registry](/hooks/notifications#event-registry)
|
||||
- [Notification Hooks](/hooks/notifications)
|
||||
243
docs/developer/addons/module-integration.mdx
Normal file
243
docs/developer/addons/module-integration.mdx
Normal file
@@ -0,0 +1,243 @@
|
||||
---
|
||||
title: Module Registry
|
||||
description: Register custom modules and addons with WooNooW's unified module system
|
||||
---
|
||||
|
||||
WooNooW's modular architecture allows developers to create custom modules and addons that integrate seamlessly with the **Settings > Modules** UI.
|
||||
|
||||
## Overview
|
||||
|
||||
The Module Registry provides a unified system for:
|
||||
- Enable/disable toggle in the admin UI
|
||||
- Custom settings with schema-based forms
|
||||
- Dependencies on other modules
|
||||
- SPA route registration for custom settings pages
|
||||
|
||||
## Registering a Module
|
||||
|
||||
Add your module using the `woonoow/modules/registry` filter:
|
||||
|
||||
```php
|
||||
add_filter('woonoow/modules/registry', 'my_plugin_register_module');
|
||||
|
||||
function my_plugin_register_module($modules) {
|
||||
$modules['my-module'] = [
|
||||
'id' => 'my-module',
|
||||
'name' => __('My Custom Module', 'my-plugin'),
|
||||
'description' => __('Description of what this module does.', 'my-plugin'),
|
||||
'icon' => 'Sparkles', // Lucide icon name
|
||||
'category' => 'marketing', // marketing, sales, developer, etc.
|
||||
'requires' => [], // Array of required module IDs
|
||||
'settings' => [], // Settings schema array
|
||||
];
|
||||
|
||||
return $modules;
|
||||
}
|
||||
```
|
||||
|
||||
## Module Properties
|
||||
|
||||
| Property | Type | Required | Description |
|
||||
|----------|------|----------|-------------|
|
||||
| `id` | string | Yes | Unique identifier (lowercase, hyphens) |
|
||||
| `name` | string | Yes | Display name in the UI |
|
||||
| `description` | string | Yes | Brief description of functionality |
|
||||
| `icon` | string | No | Lucide icon name (e.g., `Package`, `Mail`) |
|
||||
| `category` | string | No | Grouping category: `marketing`, `sales`, `developer` |
|
||||
| `requires` | array | No | Array of module IDs this depends on |
|
||||
| `settings` | array | No | Settings schema for module configuration |
|
||||
|
||||
---
|
||||
|
||||
## Settings Schema
|
||||
|
||||
Define a settings schema to allow users to configure your module:
|
||||
|
||||
```php
|
||||
'settings' => [
|
||||
[
|
||||
'id' => 'api_key',
|
||||
'type' => 'text',
|
||||
'label' => __('API Key', 'my-plugin'),
|
||||
'description' => __('Enter your API key', 'my-plugin'),
|
||||
'default' => '',
|
||||
],
|
||||
[
|
||||
'id' => 'rate_limit',
|
||||
'type' => 'number',
|
||||
'label' => __('Rate Limit', 'my-plugin'),
|
||||
'description' => __('Max requests per minute', 'my-plugin'),
|
||||
'default' => 10,
|
||||
'min' => 1,
|
||||
'max' => 100,
|
||||
],
|
||||
[
|
||||
'id' => 'enable_debug',
|
||||
'type' => 'toggle',
|
||||
'label' => __('Enable Debug Mode', 'my-plugin'),
|
||||
'default' => false,
|
||||
],
|
||||
],
|
||||
```
|
||||
|
||||
### Available Field Types
|
||||
|
||||
| Type | Description | Properties |
|
||||
|------|-------------|------------|
|
||||
| `text` | Single-line text input | `default`, `placeholder` |
|
||||
| `textarea` | Multi-line text input | `default`, `rows` |
|
||||
| `number` | Numeric input with validation | `default`, `min`, `max`, `step` |
|
||||
| `toggle` | Boolean on/off switch | `default` (true/false) |
|
||||
| `select` | Dropdown selection | `default`, `options` (array of `{value, label}`) |
|
||||
| `checkbox` | Single checkbox | `default` (true/false) |
|
||||
| `color` | Color picker | `default` (#hex value) |
|
||||
| `url` | URL input with validation | `default`, `placeholder` |
|
||||
| `email` | Email input with validation | `default`, `placeholder` |
|
||||
| `password` | Password input (masked) | `default` |
|
||||
|
||||
### Common Field Properties
|
||||
|
||||
| Property | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| `id` | string | Unique field identifier |
|
||||
| `type` | string | Field type from list above |
|
||||
| `label` | string | Display label |
|
||||
| `description` | string | Help text below field |
|
||||
| `default` | mixed | Default value |
|
||||
|
||||
### Select Field Example
|
||||
|
||||
```php
|
||||
[
|
||||
'id' => 'display_mode',
|
||||
'type' => 'select',
|
||||
'label' => __('Display Mode', 'my-plugin'),
|
||||
'default' => 'grid',
|
||||
'options' => [
|
||||
['value' => 'grid', 'label' => __('Grid', 'my-plugin')],
|
||||
['value' => 'list', 'label' => __('List', 'my-plugin')],
|
||||
['value' => 'carousel', 'label' => __('Carousel', 'my-plugin')],
|
||||
],
|
||||
],
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Checking Module Status
|
||||
|
||||
Use `ModuleRegistry::is_enabled()` to check if your module is active:
|
||||
|
||||
```php
|
||||
use WooNooW\Core\ModuleRegistry;
|
||||
|
||||
if (ModuleRegistry::is_enabled('my-module')) {
|
||||
// Module is enabled, initialize features
|
||||
My_Module_Manager::init();
|
||||
}
|
||||
```
|
||||
|
||||
## Module Lifecycle Events
|
||||
|
||||
Hook into module enable/disable events:
|
||||
|
||||
```php
|
||||
// When any module is enabled
|
||||
add_action('woonoow/module/enabled', function($module_id) {
|
||||
if ($module_id === 'my-module') {
|
||||
// Create database tables, initialize settings, etc.
|
||||
My_Module_Manager::install();
|
||||
}
|
||||
});
|
||||
|
||||
// When any module is disabled
|
||||
add_action('woonoow/module/disabled', function($module_id) {
|
||||
if ($module_id === 'my-module') {
|
||||
// Cleanup if necessary
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## SPA Routes for Settings Pages
|
||||
|
||||
Addons can register custom React settings pages:
|
||||
|
||||
```php
|
||||
add_filter('woonoow/spa_routes', function($routes) {
|
||||
$routes[] = [
|
||||
'path' => '/settings/my-addon',
|
||||
'component_url' => plugin_dir_url(__FILE__) . 'dist/Settings.js',
|
||||
'title' => 'My Addon Settings',
|
||||
];
|
||||
return $routes;
|
||||
});
|
||||
```
|
||||
|
||||
## Addon Registry (External Addons)
|
||||
|
||||
External addons can also register via `woonoow/addon_registry` for extended metadata:
|
||||
|
||||
```php
|
||||
add_filter('woonoow/addon_registry', function($addons) {
|
||||
$addons['my-shipping-addon'] = [
|
||||
'id' => 'my-shipping-addon',
|
||||
'name' => 'My Shipping',
|
||||
'description' => 'Custom shipping integration',
|
||||
'version' => '1.0.0',
|
||||
'author' => 'My Company',
|
||||
'category' => 'shipping',
|
||||
'icon' => 'truck',
|
||||
'settings_url' => '/settings/shipping/my-addon',
|
||||
'spa_bundle' => plugin_dir_url(__FILE__) . 'dist/addon.js',
|
||||
];
|
||||
return $addons;
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Complete Example
|
||||
|
||||
```php
|
||||
<?php
|
||||
namespace MyPlugin;
|
||||
|
||||
class MyModuleSettings {
|
||||
|
||||
public static function init() {
|
||||
add_filter('woonoow/modules/registry', [__CLASS__, 'register']);
|
||||
}
|
||||
|
||||
public static function register($modules) {
|
||||
$modules['my-module'] = [
|
||||
'id' => 'my-module',
|
||||
'name' => __('My Module', 'my-plugin'),
|
||||
'description' => __('Adds awesome features to your store.', 'my-plugin'),
|
||||
'icon' => 'Zap',
|
||||
'category' => 'marketing',
|
||||
'requires' => [], // No dependencies
|
||||
'settings' => [
|
||||
[
|
||||
'id' => 'feature_enabled',
|
||||
'type' => 'toggle',
|
||||
'label' => __('Enable Feature', 'my-plugin'),
|
||||
'default' => true,
|
||||
],
|
||||
],
|
||||
];
|
||||
|
||||
return $modules;
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize on plugins_loaded
|
||||
add_action('plugins_loaded', ['MyPlugin\MyModuleSettings', 'init']);
|
||||
```
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Check module status** before loading heavy features
|
||||
2. **Use the `woonoow/module/enabled` hook** to run installation routines only when needed
|
||||
3. **Specify dependencies** so WooNooW can prompt users to enable required modules
|
||||
4. **Provide meaningful descriptions** to help users understand what each module does
|
||||
103
docs/developer/addons/page-templates.mdx
Normal file
103
docs/developer/addons/page-templates.mdx
Normal file
@@ -0,0 +1,103 @@
|
||||
---
|
||||
title: Custom Page Templates
|
||||
description: Learn how to register custom starting templates for the Page Editor.
|
||||
---
|
||||
|
||||
WooNooW allows developers to register custom page templates. These templates appear in the "Create New Page" modal, allowing users to start with a pre-configured layout instead of a blank page.
|
||||
|
||||
## Registering a Template
|
||||
|
||||
To add a new template, use the `woonoow_page_templates` filter. You should append your template definition to the existing array.
|
||||
|
||||
```php
|
||||
add_filter('woonoow_page_templates', function($templates) {
|
||||
$templates[] = [
|
||||
'id' => 'my-custom-landing',
|
||||
'label' => 'Product Launch',
|
||||
'description' => 'A structured page for new product announcements.',
|
||||
'icon' => 'rocket', // Lucide icon name (lowercase)
|
||||
'sections' => [
|
||||
// Section definitions...
|
||||
]
|
||||
];
|
||||
return $templates;
|
||||
});
|
||||
```
|
||||
|
||||
## Template Structure
|
||||
|
||||
Each template requires the following properties:
|
||||
|
||||
| Property | Type | Description |
|
||||
| :--- | :--- | :--- |
|
||||
| `id` | string | Unique identifier for the template. |
|
||||
| `label` | string | Display name shown in the modal. |
|
||||
| `description` | string | Short description of the template's purpose. |
|
||||
| `icon` | string | Name of a Lucide icon (e.g., `layout`, `users`, `rocket`). |
|
||||
| `sections` | array | Array of section objects defining the initial layout. |
|
||||
|
||||
### Defining Sections
|
||||
|
||||
Sections are the building blocks of a page. Each section object mimics the structure stored in the database.
|
||||
|
||||
```php
|
||||
[
|
||||
'id' => uniqid('section_'), // Must be unique
|
||||
'type' => 'hero', // Component type (hero, feature-grid, image-text, etc.)
|
||||
'props' => [
|
||||
'title' => ['type' => 'static', 'value' => 'Hello World'],
|
||||
'subtitle' => ['type' => 'static', 'value' => 'This is a template.'],
|
||||
],
|
||||
'styles' => [
|
||||
'contentWidth' => 'contained', // 'full' or 'contained'
|
||||
'padding' => 'medium',
|
||||
]
|
||||
]
|
||||
```
|
||||
|
||||
## Example: Full Configuration
|
||||
|
||||
Here is a complete example that registers a "Support Page" template with a Hero and a FAQ section.
|
||||
|
||||
```php
|
||||
add_filter('woonoow_page_templates', function($templates) {
|
||||
$templates[] = [
|
||||
'id' => 'support-page',
|
||||
'label' => 'Support Center',
|
||||
'description' => 'Help desk layout with search and FAQ grid.',
|
||||
'icon' => 'help-circle',
|
||||
'sections' => [
|
||||
// Hero Section
|
||||
[
|
||||
'id' => uniqid('section_'),
|
||||
'type' => 'hero',
|
||||
'props' => [
|
||||
'title' => ['type' => 'static', 'value' => 'How can we help?'],
|
||||
'cta_text' => ['type' => 'static', 'value' => 'Contact Support'],
|
||||
'cta_url' => ['type' => 'static', 'value' => '/contact'],
|
||||
],
|
||||
'styles' => ['contentWidth' => 'full']
|
||||
],
|
||||
// Content Section
|
||||
[
|
||||
'id' => uniqid('section_'),
|
||||
'type' => 'content',
|
||||
'props' => [
|
||||
'content' => ['type' => 'static', 'value' => '<h2>Frequently Asked Questions</h2><p>Find answers below.</p>']
|
||||
],
|
||||
'styles' => ['contentWidth' => 'contained']
|
||||
]
|
||||
]
|
||||
];
|
||||
return $templates;
|
||||
});
|
||||
```
|
||||
|
||||
## Available Section Types
|
||||
|
||||
Common available section types include:
|
||||
- `hero`: Large banner with title, subtitle, and CTA.
|
||||
- `content`: Rich text editor content.
|
||||
- `image-text`: Split layout with image and text.
|
||||
- `feature-grid`: Grid of icons and text.
|
||||
- `cta-banner`: Call to action strip.
|
||||
79
docs/developer/addons/react-integration.mdx
Normal file
79
docs/developer/addons/react-integration.mdx
Normal file
@@ -0,0 +1,79 @@
|
||||
---
|
||||
title: React Integration
|
||||
description: Using React within WooNooW Addons
|
||||
date: 2024-01-31
|
||||
---
|
||||
|
||||
|
||||
|
||||
## The Challenge
|
||||
|
||||
External addons cannot bundle React because WooNooW already ships with a React runtime. Bundling it again would cause conflicts and bloat.
|
||||
|
||||
## Solution: Exposed Runtime
|
||||
|
||||
WooNooW exposes its React instance and Component library on the `window` object.
|
||||
|
||||
### Core Setup (How it works internally)
|
||||
|
||||
```typescript
|
||||
// WooNooW Core
|
||||
window.WooNooW = {
|
||||
React: React,
|
||||
ReactDOM: ReactDOM,
|
||||
components: {
|
||||
Button: Button,
|
||||
Input: Input,
|
||||
Select: Select,
|
||||
},
|
||||
hooks: { addFilter, addAction }
|
||||
};
|
||||
```
|
||||
|
||||
### Addon implementation
|
||||
|
||||
#### Level 1: Vanilla JS (No Build)
|
||||
|
||||
Good for simple injections.
|
||||
|
||||
```javascript
|
||||
(function() {
|
||||
window.addEventListener('woonoow:loaded', function() {
|
||||
window.WooNooW.addFilter('woonoow_order_form_after_shipping', function(container) {
|
||||
// Manual DOM manipulation
|
||||
return container;
|
||||
});
|
||||
});
|
||||
})();
|
||||
```
|
||||
|
||||
#### Level 2: React with Build (Recommended)
|
||||
|
||||
Use `vite` or `webpack` and configure React as an **external**.
|
||||
|
||||
**vite.config.js**
|
||||
```javascript
|
||||
export default {
|
||||
build: {
|
||||
rollupOptions: {
|
||||
external: ['react', 'react-dom'],
|
||||
output: {
|
||||
globals: {
|
||||
react: 'window.WooNooW.React',
|
||||
'react-dom': 'window.WooNooW.ReactDOM'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
**Index.tsx**
|
||||
```typescript
|
||||
const { React, hooks, components } = window.WooNooW;
|
||||
const { Button } = components;
|
||||
|
||||
function MyAddonComponent() {
|
||||
return <Button>Click Me</Button>;
|
||||
}
|
||||
```
|
||||
87
docs/developer/api/licensing.mdx
Normal file
87
docs/developer/api/licensing.mdx
Normal file
@@ -0,0 +1,87 @@
|
||||
---
|
||||
title: Licensing API
|
||||
description: Endpoints for activating, validating, and managing licenses
|
||||
date: 2024-01-31
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
The Licensing API allows external applications to interact with the WooNooW licensing system.
|
||||
|
||||
**Base URL**: `https://your-domain.com/wp-json/woonoow/v1`
|
||||
|
||||
---
|
||||
|
||||
## Public Endpoints
|
||||
|
||||
### Activate License
|
||||
|
||||
Activates a license key for a specific domain.
|
||||
|
||||
```http
|
||||
POST /licenses/activate
|
||||
```
|
||||
|
||||
#### Activation Parameters
|
||||
|
||||
| Body Params | Type | Required | Description |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| `license_key` | `string` | **Yes** | The license key to activate |
|
||||
| `domain` | `string` | **Yes** | The domain where the software is installed |
|
||||
| `activation_mode` | `string` | No | Set to `oauth` to trigger OAuth flow |
|
||||
|
||||
#### Responses
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"activation_id": 123,
|
||||
"license_key": "XXXX-YYYY-ZZZZ-WWWW",
|
||||
"status": "active"
|
||||
}
|
||||
```
|
||||
|
||||
If OAuth is required:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"oauth_required": true,
|
||||
"oauth_redirect": "https://vendor.com/my-account/license-connect/...",
|
||||
"state": "abc12345"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Validate License
|
||||
|
||||
Checks if a license key is valid and active for the current domain.
|
||||
|
||||
```http
|
||||
POST /licenses/validate
|
||||
```
|
||||
|
||||
#### Validation Parameters
|
||||
|
||||
| Body Params | Type | Required | Description |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| `license_key` | `string` | **Yes** | The license key to validate |
|
||||
| `domain` | `string` | **Yes** | The domain to check against |
|
||||
|
||||
---
|
||||
|
||||
### Deactivate License
|
||||
|
||||
Deactivates a license for the current domain.
|
||||
|
||||
```http
|
||||
POST /licenses/deactivate
|
||||
```
|
||||
|
||||
#### Deactivation Parameters
|
||||
|
||||
| Body Params | Type | Required | Description |
|
||||
| :--- | :--- | :--- | :--- |
|
||||
| `license_key` | `string` | **Yes** | The license key to deactivate |
|
||||
| `domain` | `string` | **Yes** | The domain to remove |
|
||||
20
docs/developer/overview.mdx
Normal file
20
docs/developer/overview.mdx
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
title: Developer Guide
|
||||
description: Extend and customize WooNooW.
|
||||
---
|
||||
|
||||
## Core Concepts
|
||||
|
||||
WooNooW is built with extensibility in mind.
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Addons System" icon="Package" href="/docs/developer/addons/module-integration">
|
||||
Learn how to create custom modules that plug into the WooNooW ecosystem.
|
||||
</Card>
|
||||
<Card title="React Integration" icon="Plug" href="/docs/developer/addons/react-integration">
|
||||
Understand how we bridge PHP and React to create seamless admin interfaces.
|
||||
</Card>
|
||||
<Card title="API Reference" icon="Zap" href="/docs/developer/api/licensing">
|
||||
Detailed documentation of our REST API endpoints.
|
||||
</Card>
|
||||
</CardGroup>
|
||||
218
docs/developer/software-updates/index.mdx
Normal file
218
docs/developer/software-updates/index.mdx
Normal file
@@ -0,0 +1,218 @@
|
||||
---
|
||||
title: Software Updates API
|
||||
description: Distribute software updates with license-based access control
|
||||
---
|
||||
|
||||
The Software Distribution module enables selling WordPress plugins, themes, or any software with automatic update checking, secure downloads, and version management.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Enable **Licensing** module (required)
|
||||
- Enable **Software Distribution** module in Settings → Modules
|
||||
- Configure downloadable products with software distribution enabled
|
||||
|
||||
## Product Configuration
|
||||
|
||||
When editing a downloadable product in WooCommerce, you'll see a new "Software Distribution" section:
|
||||
|
||||
| Field | Description |
|
||||
|-------|-------------|
|
||||
| **Enable Software Updates** | Allow customers to check for updates via API |
|
||||
| **Software Slug** | Unique identifier (e.g., `my-plugin`) used in API calls |
|
||||
| **Current Version** | Latest version number (e.g., `1.2.3`) |
|
||||
|
||||
### WordPress Integration (Optional)
|
||||
|
||||
Enable "WordPress Plugin/Theme" to add these fields:
|
||||
|
||||
- **Requires WP** - Minimum WordPress version
|
||||
- **Tested WP** - Tested up to WordPress version
|
||||
- **Requires PHP** - Minimum PHP version
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Check for Updates
|
||||
|
||||
```
|
||||
GET /wp-json/woonoow/v1/software/check
|
||||
POST /wp-json/woonoow/v1/software/check
|
||||
```
|
||||
|
||||
**Parameters:**
|
||||
|
||||
| Parameter | Type | Required | Description |
|
||||
|-----------|------|----------|-------------|
|
||||
| `license_key` | string | Yes | Valid license key |
|
||||
| `slug` | string | Yes | Software slug |
|
||||
| `version` | string | Yes | Current installed version |
|
||||
| `site_url` | string | No | Site URL for tracking |
|
||||
|
||||
**Response:**
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"update_available": true,
|
||||
"product": {
|
||||
"name": "My Plugin",
|
||||
"slug": "my-plugin"
|
||||
},
|
||||
"current_version": "1.0.0",
|
||||
"latest_version": "1.2.0",
|
||||
"changelog": "## What's New\n- Added feature X\n- Fixed bug Y",
|
||||
"release_date": "2026-02-01 12:00:00",
|
||||
"download_url": "https://your-store.com/wp-json/woonoow/v1/software/download?token=..."
|
||||
}
|
||||
```
|
||||
|
||||
For WordPress plugins/themes, an additional `wordpress` object is included:
|
||||
|
||||
```json
|
||||
{
|
||||
"wordpress": {
|
||||
"requires": "6.0",
|
||||
"tested": "6.7",
|
||||
"requires_php": "7.4",
|
||||
"icons": { "1x": "...", "2x": "..." },
|
||||
"banners": { "low": "...", "high": "..." }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Download File
|
||||
|
||||
```
|
||||
GET /wp-json/woonoow/v1/software/download?token=<token>
|
||||
```
|
||||
|
||||
Download tokens are single-use and expire after 5 minutes.
|
||||
|
||||
### Get Changelog
|
||||
|
||||
```
|
||||
GET /wp-json/woonoow/v1/software/changelog?slug=<slug>
|
||||
GET /wp-json/woonoow/v1/software/changelog?slug=<slug>&version=<version>
|
||||
```
|
||||
|
||||
Returns version history with changelogs.
|
||||
|
||||
## WordPress Client Integration
|
||||
|
||||
Include the updater class in your plugin or theme to enable automatic updates:
|
||||
|
||||
### 1. Copy the Updater Class
|
||||
|
||||
Copy `class-woonoow-updater.php` from the WooNooW plugin's `templates/updater/` directory to your plugin.
|
||||
|
||||
### 2. Initialize in Your Plugin
|
||||
|
||||
```php
|
||||
<?php
|
||||
// In your main plugin file
|
||||
|
||||
require_once plugin_dir_path(__FILE__) . 'includes/class-woonoow-updater.php';
|
||||
|
||||
new WooNooW_Updater([
|
||||
'api_url' => 'https://your-store.com/',
|
||||
'slug' => 'my-plugin',
|
||||
'version' => MY_PLUGIN_VERSION,
|
||||
'license_key' => get_option('my_plugin_license_key'),
|
||||
'plugin_file' => __FILE__,
|
||||
]);
|
||||
```
|
||||
|
||||
### 3. For Themes
|
||||
|
||||
```php
|
||||
<?php
|
||||
// In your theme's functions.php
|
||||
|
||||
require_once get_theme_file_path('includes/class-woonoow-updater.php');
|
||||
|
||||
new WooNooW_Updater([
|
||||
'api_url' => 'https://your-store.com/',
|
||||
'slug' => 'my-theme',
|
||||
'version' => wp_get_theme()->get('Version'),
|
||||
'license_key' => get_option('my_theme_license_key'),
|
||||
'theme_slug' => 'my-theme',
|
||||
]);
|
||||
```
|
||||
|
||||
## Non-WordPress Integration
|
||||
|
||||
For other software types, make HTTP requests directly to the API:
|
||||
|
||||
### JavaScript Example
|
||||
|
||||
```javascript
|
||||
async function checkForUpdates(licenseKey, currentVersion) {
|
||||
const response = await fetch('https://your-store.com/wp-json/woonoow/v1/software/check', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
license_key: licenseKey,
|
||||
slug: 'my-software',
|
||||
version: currentVersion,
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (data.update_available) {
|
||||
console.log(`Update available: v${data.latest_version}`);
|
||||
// Download from data.download_url
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
```
|
||||
|
||||
### Python Example
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
def check_for_updates(license_key: str, current_version: str) -> dict:
|
||||
response = requests.post(
|
||||
'https://your-store.com/wp-json/woonoow/v1/software/check',
|
||||
json={
|
||||
'license_key': license_key,
|
||||
'slug': 'my-software',
|
||||
'version': current_version,
|
||||
}
|
||||
)
|
||||
|
||||
data = response.json()
|
||||
|
||||
if data.get('update_available'):
|
||||
print(f"Update available: v{data['latest_version']}")
|
||||
# Download from data['download_url']
|
||||
|
||||
return data
|
||||
```
|
||||
|
||||
## Managing Versions
|
||||
|
||||
Use the Admin SPA at **Products → Software Versions** to:
|
||||
|
||||
- View all software-enabled products
|
||||
- Release new versions with changelogs
|
||||
- Track download counts per version
|
||||
- Set current (latest) version
|
||||
|
||||
## Error Codes
|
||||
|
||||
| Error | Description |
|
||||
|-------|-------------|
|
||||
| `invalid_license` | License key is invalid or expired |
|
||||
| `product_not_found` | Software slug doesn't match any product |
|
||||
| `software_disabled` | Software distribution not enabled for product |
|
||||
| `invalid_token` | Download token expired or already used |
|
||||
| `module_disabled` | Software Distribution module is disabled |
|
||||
|
||||
## Security
|
||||
|
||||
- All API endpoints require valid license key
|
||||
- Download tokens are single-use and expire in 5 minutes
|
||||
- Rate limiting: 10 requests/minute per license (configurable)
|
||||
- IP address logged with download tokens
|
||||
45
docs/developer/software-updates/store-owner.mdx
Normal file
45
docs/developer/software-updates/store-owner.mdx
Normal file
@@ -0,0 +1,45 @@
|
||||
---
|
||||
title: Store Owner Guide
|
||||
description: Managing and distributing digital software products.
|
||||
---
|
||||
|
||||
WooNooW's Software Updates module allows you to securely sell, distribute, and manage updates for your digital products, plugins, or applications.
|
||||
|
||||
## Enabling the Software Module
|
||||
To begin distributing software, you must first enable the module:
|
||||
1. Navigate to **WooNooW > Settings > Modules**.
|
||||
2. Toggle on the **Software Updates** module.
|
||||
3. Save changes.
|
||||
|
||||
## Creating a Software Product
|
||||
Software products are created by extending standard WooCommerce virtual products.
|
||||
|
||||
1. Go to **Products > Add New** in WordPress.
|
||||
2. Check both the **Virtual** and **Downloadable** checkboxes in the Product Data panel.
|
||||
3. In the left tabs, select **Software Details**.
|
||||
4. Configure the following specific to your software:
|
||||
- **Software Type:** Identify the platform (e.g., WordPress Plugin, Desktop App).
|
||||
- **Current Version:** The latest release version (e.g., 1.2.0).
|
||||
- **Requires PHP/WP:** Set minimum system requirements (optional).
|
||||
- **Tested Up To:** Set the maximum compatible platform version (optional).
|
||||
5. Add your downloadable file under the standard **Downloadable** tab.
|
||||
6. Publish the product.
|
||||
|
||||
## Managing Version History
|
||||
When you release an update:
|
||||
1. Navigate to **Store > Software Versions** in your WooNooW Admin SPA.
|
||||
2. Click **Create Release**.
|
||||
3. Select the software product you are updating.
|
||||
4. Enter the new **Version Number** (e.g., 1.3.0).
|
||||
5. Provide a detailed **Changelog**. Use Markdown to list features, fixes, and notes.
|
||||
6. Publish the release.
|
||||
|
||||
When customers check for updates within their application (using the API), the system will serve them the latest version and display this changelog.
|
||||
|
||||
## Licensing
|
||||
You can choose to attach License Keys to your software to prevent unauthorized use.
|
||||
1. Enable the **Licensing** module in Settings.
|
||||
2. When configuring your Software Product, check the **Requires License** box.
|
||||
3. Define the activation limit (e.g., 1 site, 5 sites, or unlimited).
|
||||
|
||||
When a customer purchases the software, the system will automatically generate a unique license key and deliver it in the checkout confirmation and email receipt. Customers can manage their active activations from their **My Account > Licenses** dashboard.
|
||||
Reference in New Issue
Block a user