Files
WooNooW/ADDON_INJECTION_GUIDE.md
dwindown 232059e928 feat: Complete Dashboard API Integration with Analytics Controller
 Features:
- Implemented API integration for all 7 dashboard pages
- Added Analytics REST API controller with 7 endpoints
- Full loading and error states with retry functionality
- Seamless dummy data toggle for development

📊 Dashboard Pages:
- Customers Analytics (complete)
- Revenue Analytics (complete)
- Orders Analytics (complete)
- Products Analytics (complete)
- Coupons Analytics (complete)
- Taxes Analytics (complete)
- Dashboard Overview (complete)

🔌 Backend:
- Created AnalyticsController.php with REST endpoints
- All endpoints return 501 (Not Implemented) for now
- Ready for HPOS-based implementation
- Proper permission checks

🎨 Frontend:
- useAnalytics hook for data fetching
- React Query caching
- ErrorCard with retry functionality
- TypeScript type safety
- Zero build errors

📝 Documentation:
- DASHBOARD_API_IMPLEMENTATION.md guide
- Backend implementation roadmap
- Testing strategy

🔧 Build:
- All pages compile successfully
- Production-ready with dummy data fallback
- Zero TypeScript errors
2025-11-04 11:19:00 +07:00

16 KiB

WooNooW Addon Injection Guide

Version: 1.0.0
Last Updated: 2025-10-28
Status: Production Ready


📋 Table of Contents

  1. Overview
  2. Admin SPA Addons
  3. Customer SPA Addons (Coming Soon)
  4. Testing & Debugging
  5. Examples
  6. Troubleshooting

Overview

WooNooW provides a powerful addon injection system that allows third-party plugins to seamlessly integrate with the React-powered admin SPA. Addons can:

  • Register custom SPA routes
  • Inject navigation menu items
  • Add submenu items to existing sections
  • Load React components dynamically
  • Declare dependencies and capabilities
  • Maintain full isolation and safety

No iframes, no hacks, just clean React integration!


Admin SPA Addons

Quick Start

5-Minute Integration:

<?php
/**
 * Plugin Name: My WooNooW Addon
 * Description: Adds custom functionality to WooNooW
 * Version: 1.0.0
 */

// 1. Register your addon
add_filter('woonoow/addon_registry', function($addons) {
    $addons['my-addon'] = [
        'id'           => 'my-addon',
        'name'         => 'My Addon',
        'version'      => '1.0.0',
        'author'       => 'Your Name',
        'description'  => 'My awesome addon',
        'spa_bundle'   => plugin_dir_url(__FILE__) . 'dist/addon.js',
        'dependencies' => ['woocommerce' => '8.0'],
    ];
    return $addons;
});

// 2. Register your routes
add_filter('woonoow/spa_routes', function($routes) {
    $routes[] = [
        'path'          => '/my-addon',
        'component_url' => plugin_dir_url(__FILE__) . 'dist/MyAddonPage.js',
        'capability'    => 'manage_woocommerce',
        'title'         => 'My Addon',
    ];
    return $routes;
});

// 3. Add navigation item
add_filter('woonoow/nav_tree', function($tree) {
    $tree[] = [
        'key'      => 'my-addon',
        'label'    => 'My Addon',
        'path'     => '/my-addon',
        'icon'     => 'puzzle', // lucide icon name
        'children' => [],
    ];
    return $tree;
});

That's it! Your addon is now integrated into WooNooW.


Addon Registration

Filter: woonoow/addon_registry
Priority: 20 (runs on plugins_loaded)
File: includes/Compat/AddonRegistry.php

Configuration Schema

add_filter('woonoow/addon_registry', function($addons) {
    $addons['addon-id'] = [
        // Required
        'id'           => 'addon-id',        // Unique identifier
        'name'         => 'Addon Name',      // Display name
        'version'      => '1.0.0',           // Semantic version
        
        // Optional
        'author'       => 'Author Name',     // Author name
        'description'  => 'Description',     // Short description
        'spa_bundle'   => 'https://...',     // Main JS bundle URL
        
        // Dependencies (optional)
        'dependencies' => [
            'woocommerce' => '8.0',          // Min WooCommerce version
            'wordpress'   => '6.0',          // Min WordPress version
        ],
        
        // Advanced (optional)
        'routes'       => [],                // Route definitions
        'nav_items'    => [],                // Nav item definitions
        'widgets'      => [],                // Widget definitions
    ];
    return $addons;
});

Dependency Validation

WooNooW automatically validates dependencies:

'dependencies' => [
    'woocommerce' => '8.0',  // Requires WooCommerce 8.0+
    'wordpress'   => '6.4',  // Requires WordPress 6.4+
]

If dependencies are not met:

  • Addon is disabled automatically
  • Routes are not registered
  • Navigation items are hidden

Route Registration

Filter: woonoow/spa_routes
Priority: 25 (runs on plugins_loaded)
File: includes/Compat/RouteRegistry.php

Basic Route

add_filter('woonoow/spa_routes', function($routes) {
    $routes[] = [
        'path'          => '/subscriptions',
        'component_url' => plugin_dir_url(__FILE__) . 'dist/SubscriptionsList.js',
        'capability'    => 'manage_woocommerce',
        'title'         => 'Subscriptions',
    ];
    return $routes;
});

Multiple Routes

add_filter('woonoow/spa_routes', function($routes) {
    $base_url = plugin_dir_url(__FILE__) . 'dist/';
    
    $routes[] = [
        'path'          => '/subscriptions',
        'component_url' => $base_url . 'SubscriptionsList.js',
        'capability'    => 'manage_woocommerce',
        'title'         => 'All Subscriptions',
    ];
    
    $routes[] = [
        'path'          => '/subscriptions/new',
        'component_url' => $base_url . 'SubscriptionNew.js',
        'capability'    => 'manage_woocommerce',
        'title'         => 'New Subscription',
    ];
    
    $routes[] = [
        'path'          => '/subscriptions/:id',
        'component_url' => $base_url . 'SubscriptionDetail.js',
        'capability'    => 'manage_woocommerce',
        'title'         => 'Subscription Detail',
    ];
    
    return $routes;
});

Route Configuration

Property Type Required Description
path string Yes Route path (must start with /)
component_url string Yes URL to React component JS file
capability string No WordPress capability (default: manage_woocommerce)
title string No Page title
exact boolean No Exact path match (default: false)
props object No Props to pass to component

Navigation Injection

Add Main Menu Item

Filter: woonoow/nav_tree
Priority: 30 (runs on plugins_loaded)
File: includes/Compat/NavigationRegistry.php

add_filter('woonoow/nav_tree', function($tree) {
    $tree[] = [
        'key'      => 'subscriptions',
        'label'    => __('Subscriptions', 'my-addon'),
        'path'     => '/subscriptions',
        'icon'     => 'repeat', // lucide-react icon name
        'children' => [
            [
                'label' => __('All Subscriptions', 'my-addon'),
                'mode'  => 'spa',
                'path'  => '/subscriptions',
            ],
            [
                'label' => __('New', 'my-addon'),
                'mode'  => 'spa',
                'path'  => '/subscriptions/new',
            ],
        ],
    ];
    return $tree;
});

Inject into Existing Section

Filter: woonoow/nav_tree/{key}/children

// Add "Bundles" to Products menu
add_filter('woonoow/nav_tree/products/children', function($children) {
    $children[] = [
        'label' => __('Bundles', 'my-addon'),
        'mode'  => 'spa',
        'path'  => '/products/bundles',
    ];
    return $children;
});

// Add "Reports" to Dashboard menu
add_filter('woonoow/nav_tree/dashboard/children', function($children) {
    $children[] = [
        'label' => __('Custom Reports', 'my-addon'),
        'mode'  => 'spa',
        'path'  => '/reports',
    ];
    return $children;
});

Available Sections

Key Label Path
dashboard Dashboard /
orders Orders /orders
products Products /products
coupons Coupons /coupons
customers Customers /customers
settings Settings /settings

Navigation Item Schema

{
  key: string;           // Unique key (for main items)
  label: string;         // Display label (i18n recommended)
  path: string;          // Route path
  icon?: string;         // Lucide icon name (main items only)
  mode: 'spa' | 'bridge'; // Render mode
  href?: string;         // External URL (bridge mode)
  exact?: boolean;       // Exact path match
  children?: SubItem[];  // Submenu items
}

Lucide Icons

WooNooW uses lucide-react icons (16-20px, 1.5px stroke).

Popular icons:

  • layout-dashboard - Dashboard
  • receipt-text - Orders
  • package - Products
  • tag - Coupons
  • users - Customers
  • settings - Settings
  • repeat - Subscriptions
  • calendar - Bookings
  • credit-card - Payments
  • bar-chart - Analytics

Component Development

Component Structure

Your React component will be dynamically imported and rendered:

// dist/MyAddonPage.tsx
import React from 'react';

export default function MyAddonPage(props: any) {
  return (
    <div className="space-y-6">
      <div className="rounded-lg border border-border p-6 bg-card">
        <h2 className="text-xl font-semibold mb-2">My Addon</h2>
        <p className="text-sm opacity-70">Welcome to my addon!</p>
      </div>
    </div>
  );
}

Access WooNooW APIs

// Access REST API
const api = (window as any).WNW_API;
const response = await fetch(`${api.root}my-addon/endpoint`, {
  headers: {
    'X-WP-Nonce': api.nonce,
  },
});

// Access store data
const store = (window as any).WNW_STORE;
console.log('Currency:', store.currency);
console.log('Symbol:', store.currency_symbol);

// Access site info
const wnw = (window as any).wnw;
console.log('Site Title:', wnw.siteTitle);
console.log('Admin URL:', wnw.adminUrl);

Use WooNooW Components

import { __ } from '@/lib/i18n';
import { formatMoney } from '@/lib/currency';
import { Button } from '@/components/ui/button';
import { Card } from '@/components/ui/card';

export default function MyAddonPage() {
  return (
    <Card className="p-6">
      <h2>{__('My Addon', 'my-addon')}</h2>
      <p>{formatMoney(1234.56)}</p>
      <Button>{__('Click Me', 'my-addon')}</Button>
    </Card>
  );
}

Build Your Component

Using Vite:

// vite.config.js
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';

export default defineConfig({
  plugins: [react()],
  build: {
    lib: {
      entry: 'src/MyAddonPage.tsx',
      name: 'MyAddon',
      fileName: 'MyAddonPage',
      formats: ['es'],
    },
    rollupOptions: {
      external: ['react', 'react-dom'],
      output: {
        globals: {
          react: 'React',
          'react-dom': 'ReactDOM',
        },
      },
    },
  },
});
npm run build

Best Practices

DO:

  1. Use Semantic Versioning

    'version' => '1.2.3'
    
  2. Declare Dependencies

    'dependencies' => ['woocommerce' => '8.0']
    
  3. Check Capabilities

    'capability' => 'manage_woocommerce'
    
  4. Internationalize Strings

    'label' => __('Subscriptions', 'my-addon')
    
  5. Use Namespaced Hooks

    add_filter('woonoow/addon_registry', ...)
    
  6. Validate User Input

    $value = sanitize_text_field($_POST['value']);
    
  7. Handle Errors Gracefully

    try {
      // Load component
    } catch (error) {
      // Show error message
    }
    
  8. Follow WooNooW UI Patterns

    • Use Tailwind CSS classes
    • Use Shadcn UI components
    • Follow mobile-first design
    • Use .ui-ctrl class for controls

DON'T:

  1. Don't Hardcode URLs

    // ❌ Bad
    'component_url' => 'https://mysite.com/addon.js'
    
    // ✅ Good
    'component_url' => plugin_dir_url(__FILE__) . 'dist/addon.js'
    
  2. Don't Skip Capability Checks

    // ❌ Bad
    'capability' => ''
    
    // ✅ Good
    'capability' => 'manage_woocommerce'
    
  3. Don't Use Generic Hook Names

    // ❌ Bad
    add_filter('addon_registry', ...)
    
    // ✅ Good
    add_filter('woonoow/addon_registry', ...)
    
  4. Don't Modify Core Navigation

    // ❌ Bad - Don't remove core items
    unset($tree[0]);
    
    // ✅ Good - Add your own items
    $tree[] = ['key' => 'my-addon', ...];
    
  5. Don't Block the Main Thread

    // ❌ Bad
    while (loading) { /* wait */ }
    
    // ✅ Good
    if (loading) return <Loader />;
    
  6. Don't Use Inline Styles

    // ❌ Bad
    <div style={{color: 'red'}}>
    
    // ✅ Good
    <div className="text-red-600">
    

Customer SPA Addons

Status: 🚧 Coming Soon

Customer SPA addon injection will support:

  • Cart page customization
  • Checkout step injection
  • My Account page tabs
  • Widget areas
  • Custom forms

Stay tuned for updates!


Testing & Debugging

Enable Debug Mode

// wp-config.php
define('WNW_DEV', true);

This enables:

  • Console logging
  • Cache flushing
  • Detailed error messages

Check Addon Registration

// Browser console
console.log(window.WNW_ADDONS);
console.log(window.WNW_ADDON_ROUTES);
console.log(window.WNW_NAV_TREE);

Flush Caches

// Programmatically
do_action('woonoow_flush_caches');

// Or via URL (admins only)
// https://yoursite.com/wp-admin/?flush_wnw_cache=1

Common Issues

Addon not appearing?

  • Check dependencies are met
  • Verify capability requirements
  • Check browser console for errors
  • Flush caches

Route not loading?

  • Verify component_url is correct
  • Check file exists and is accessible
  • Look for JS errors in console
  • Ensure component exports default

Navigation not showing?

  • Check filter priority
  • Verify path matches route
  • Check i18n strings load
  • Inspect window.WNW_NAV_TREE

Examples

Example 1: Simple Addon

<?php
/**
 * Plugin Name: WooNooW Hello World
 * Description: Minimal addon example
 * Version: 1.0.0
 */

add_filter('woonoow/addon_registry', function($addons) {
    $addons['hello-world'] = [
        'id'      => 'hello-world',
        'name'    => 'Hello World',
        'version' => '1.0.0',
    ];
    return $addons;
});

add_filter('woonoow/spa_routes', function($routes) {
    $routes[] = [
        'path'          => '/hello',
        'component_url' => plugin_dir_url(__FILE__) . 'dist/Hello.js',
        'capability'    => 'read', // All logged-in users
        'title'         => 'Hello World',
    ];
    return $routes;
});

add_filter('woonoow/nav_tree', function($tree) {
    $tree[] = [
        'key'   => 'hello',
        'label' => 'Hello',
        'path'  => '/hello',
        'icon'  => 'smile',
        'children' => [],
    ];
    return $tree;
});
// dist/Hello.tsx
import React from 'react';

export default function Hello() {
  return (
    <div className="p-6">
      <h1 className="text-2xl font-bold">Hello, WooNooW!</h1>
    </div>
  );
}

See ADDON_INJECTION_READINESS_REPORT.md for the complete Subscriptions addon example.


Troubleshooting

Addon Registry Issues

Problem: Addon not registered

Solutions:

  1. Check plugins_loaded hook fires
  2. Verify filter name: woonoow/addon_registry
  3. Check dependencies are met
  4. Look for PHP errors in debug log

Route Issues

Problem: Route returns 404

Solutions:

  1. Verify path starts with /
  2. Check component_url is accessible
  3. Ensure route is registered before navigation
  4. Check capability requirements

Navigation Issues

Problem: Menu item not showing

Solutions:

  1. Check filter: woonoow/nav_tree or woonoow/nav_tree/{key}/children
  2. Verify path matches registered route
  3. Check i18n strings are loaded
  4. Inspect window.WNW_NAV_TREE in console

Component Loading Issues

Problem: Component fails to load

Solutions:

  1. Check component exports default
  2. Verify file is built correctly
  3. Check for JS errors in console
  4. Ensure React/ReactDOM are available
  5. Test component URL directly in browser

Support & Resources

Documentation:

  • ADDON_INJECTION_READINESS_REPORT.md - Technical analysis
  • ADDONS_ADMIN_UI_REQUIREMENTS.md - Requirements & status
  • PROGRESS_NOTE.md - Development progress

Code References:

  • includes/Compat/AddonRegistry.php - Addon registration
  • includes/Compat/RouteRegistry.php - Route management
  • includes/Compat/NavigationRegistry.php - Navigation building
  • admin-spa/src/App.tsx - Dynamic route loading
  • admin-spa/src/nav/tree.ts - Navigation tree

Community:

  • GitHub Issues: Report bugs
  • Discussions: Ask questions
  • Examples: Share your addons

End of Guide

Version: 1.0.0
Last Updated: 2025-10-28
Status: Production Ready