# Affiliate Module - Implementation Report **Document Version:** 1.0 **Date:** 2026-05-31 **Module:** WooNooW Affiliate Program --- ## Table of Contents 1. [Implementation Summary](#implementation-summary) 2. [Backend (PHP)](#backend-php) 3. [Admin SPA](#admin-spa) 4. [Customer SPA](#customer-spa) 5. [Gaps & Defects](#gaps--defects) 6. [Opportunities](#opportunities) --- ## Implementation Summary | Area | Status | Coverage | Production Ready | |------|--------|----------|-----------------| | Referral Tracking | Working (Main Path) | ~90% | ⚠️ | | Order Lifecycle | Partial | ~70% | ⚠️ | | Backend API | Partial | ~70% | ⚠️ | | Customer Dashboard | Partial | ~60% | ⚠️ | | Admin SPA | Partial | ~50% | ⚠️ | | Email Notifications | Partial | ~50% | ⚠️ | | Payout System | Placeholder | 0% | ❌ | **Overall Assessment:** Foundation is solid with clean architecture. Referral tracking works for standard page-load checkout flows, but still needs hardening for block-based checkout and dynamic URL handling. Payout system is the critical gap preventing production use. ### What Works Well - **Clean separation of concerns** — Module bootstrap, tracking, lifecycle, settings are distinct files - **Multiple checkout hooks** — Works with legacy checkout and admin order creation - **Order lifecycle handling** — Refunds/cancellations properly reject referrals with clawback - **Customer dashboard** — Functional with proper currency formatting - **Admin order integration** — Shows affiliate attribution in order details ### What's Working (Main Path) - Cookie-based referral tracking on standard page loads - Affiliate application and approval flow - Commission calculation on order completion - Auto-approval via Action Scheduler after holding period - Order refund/cancellation → referral rejection with clawback ### What's Still Needs Hardening - **Block checkout compatibility** — Cookie capture relies on `init` hook; may miss AJAX-based checkout flows - **Dynamic referral link** — Current implementation assumes `/shop` path; needs site-config-aware URL generation - **Edge case handling** — Invalid referral codes, expired cookies, cross-device attribution not fully tested ### What's Missing for Production 1. **Payout workflow** — Cannot pay affiliates (blocking) 2. **Per-affiliate commission override** — No custom rates (high priority) 3. **Self-referral override** — No admin whitelist (high priority) 4. **Referral detail transparency** — Customer can't see order details (medium) --- ## Backend (PHP) ### Files Implemented | File | Path | Purpose | |------|------|---------| | AffiliateModule.php | `/includes/Modules/Affiliate/` | Bootstrap & initialization | | AffiliateManager.php | `/includes/Modules/Affiliate/` | Database table creation | | AffiliateTracker.php | `/includes/Modules/Affiliate/` | Referral tracking & cookie handling | | AffiliateLifecycle.php | `/includes/Modules/Affiliate/` | Order status/cancellation handling | | AffiliateSettings.php | `/includes/Modules/Affiliate/` | Module settings schema | | AffiliateAdminController.php | `/includes/Api/Controllers/` | Admin API endpoints | | AffiliateCustomerController.php | `/includes/Api/Controllers/` | Customer API endpoints | ### Database Tables #### `wp_woonoow_affiliates` | Column | Type | Notes | |--------|------|-------| | id | bigint | Primary key | | user_id | bigint | Links to WP users | | referral_code | varchar(50) | Unique affiliate code | | coupon_id | bigint | Optional WC coupon link | | commission_rate | decimal(10,2) | Percentage | | status | varchar(20) | pending/active/rejected | | total_referrals | int | Counter | | total_earnings | decimal(19,4) | Accumulated earnings | | paid_earnings | decimal(19,4) | Paid out amount | | created_at | datetime | | | updated_at | datetime | Auto-update | #### `wp_woonoow_referrals` | Column | Type | Notes | |--------|------|-------| | id | bigint | Primary key | | affiliate_id | bigint | FK to affiliates | | order_id | bigint | WooCommerce order | | customer_id | bigint | Customer user ID | | commission_amount | decimal(19,4) | Calculated commission | | currency | varchar(10) | Default USD | | status | varchar(20) | pending/approved/rejected | | cancelled_reason | varchar(50) | WHY rejected | | cancelled_at | datetime | When cancelled | | created_at | datetime | | | approved_at | datetime | When approved | | paid_at | datetime | When paid | #### `wp_woonoow_affiliate_payouts` | Column | Type | Notes | |--------|------|-------| | id | bigint | Primary key | | affiliate_id | bigint | FK | | amount | decimal(19,4) | | | currency | varchar(10) | | | method | varchar(50) | Payment method | | status | varchar(20) | pending/completed | | notes | text | | | created_at | datetime | | | completed_at | datetime | | ### API Endpoints #### Admin Endpoints (`/woonoow/v1/admin/affiliates`) | Method | Endpoint | Function | Implemented | |--------|----------|----------|-------------| | GET | `/` | `get_affiliates()` | ✅ | | POST | `/(?P\d+)/approve` | `approve_affiliate()` | ✅ | | GET | `/referrals` | `get_referrals()` | ✅ | | POST | `/payouts` | `create_payout()` | ✅ | #### Customer Endpoints (`/woonoow/v1/account/affiliate`) | Method | Endpoint | Function | Implemented | |--------|----------|----------|-------------| | GET | `/` | `get_dashboard()` | ✅ | | POST | `/apply` | `apply_affiliate()` | ✅ | | GET | `/referrals` | `get_referrals()` | ✅ | ### Hooks & Tracking | Hook | Handler | Status | Notes | |------|---------|--------|-------| | `init` | `capture_referral_link()` | ✅ | Captures `?ref=` from URL | | `woocommerce_checkout_order_processed` | `record_referral()` | ✅ | Legacy checkout | | `woocommerce_store_api_checkout_order_processed` | `record_referral_block()` | ✅ | Block checkout (WC 8.3+) | | `woocommerce_new_order` | `record_referral_new_order()` | ✅ | Universal fallback | | `woocommerce_process_shop_order_meta` | `record_referral_admin()` | ✅ | Admin order creation | | `woocommerce_order_status_refunded` | `handle_order_cancelled()` | ✅ | | | `woocommerce_order_status_cancelled` | `handle_order_cancelled()` | ✅ | | | `woocommerce_order_status_failed` | `handle_order_cancelled()` | ✅ | | | `before_delete_post` | `handle_order_deleted()` | ✅ | | | `woocommerce_delete_order` | `handle_order_deleted()` | ✅ | | **Tracking Coverage:** All WooCommerce order creation paths are hooked. Cookie capture works on standard page loads. ### Email Notifications | Event ID | Template | Status | |----------|----------|--------| | `affiliate_application_received` | Staff notification | ✅ | | `affiliate_application_approved` | Customer welcome | ✅ | | `affiliate_new_referral` | Commission earned | ✅ | --- ## Admin SPA ### Routes | Route | Component | Implemented | |-------|-----------|-------------| | `/marketing/affiliates` | AffiliatesLayout | ✅ | | `/marketing/affiliates/list` | AffiliatesList | ✅ | | `/marketing/affiliates/referrals` | AffiliatesReferrals | ✅ | | `/marketing/affiliates/payouts` | AffiliatesPayouts | ⚠️ Placeholder | ### Features Implemented #### AffiliatesList - Search by referral code - Display table: User ID, Code, Rate, Status, Earnings, Actions - Approve button for pending affiliates - Status badges (color-coded) #### AffiliatesReferrals - Display all referrals table - Columns: ID, Affiliate ID, Order ID, Status, Date, Commission - Status badges #### AffiliatesPayouts - **NOT IMPLEMENTED** - Shows "coming soon" placeholder ### Order Details Integration The order detail page (`/orders/{id}`) now shows affiliate information: - Affiliate name - Commission rate - Commission amount - Status with cancellation reason --- ## Customer SPA ### Routes | Route | Component | Implemented | |-------|-----------|-------------| | `/my-account/affiliate` | AffiliateDashboard | ✅ | ### Features Implemented #### Application Flow - "Join Affiliate Program" card with Apply Now button - Pending status notification when awaiting approval #### Dashboard (Active Affiliates) - Total Earnings card - Pending Earnings card - Commission Rate display - Referral link generator with copy button - Recent Referrals table ### Format Issues (Fixed) - Currency formatting now uses site's WooCommerce settings - IDR displays as `Rp19.900` (no decimals, thousand separator) - Other currencies use configured decimals --- ## Gaps & Defects ### Critical (Blocking) #### 1. Payout System Not Functional **Location:** Admin & Backend **Severity:** Critical **Issue:** The payout creation API (`create_payout()`) exists but: - No UI to initiate payouts in Admin SPA (placeholder only) - No calculation of payable balance (`total_earnings - paid_earnings`) - No payout history view - No payment processing (only store_credit implemented) **Impact:** Cannot pay affiliates — program is incomplete **Required Fix:** ```php // AffiliateAdminController.php public static function get_affiliate_balance($affiliate_id) { global $wpdb; $table = $wpdb->prefix . 'woonoow_affiliates'; $affiliate = $wpdb->get_row($wpdb->prepare( "SELECT total_earnings, paid_earnings FROM $table WHERE id = %d", $affiliate_id )); return [ 'total_earnings' => (float) $affiliate->total_earnings, 'paid_earnings' => (float) $affiliate->paid_earnings, 'payable_balance' => (float) $affiliate->total_earnings - (float) $affiliate->paid_earnings ]; } ``` #### 2. Referral Link Hardcoded to `/shop` **Location:** Customer SPA - AffiliateDashboard.tsx **Severity:** Critical **Issue:** ```typescript // Current (hardcoded) const referralLink = `${window.location.origin}${window.location.pathname.replace('/my-account/affiliate', '/shop')}?ref=${profile.referral_code}`; ``` - Assumes shop page exists at `/shop` - Doesn't check site's actual SPA mode or base path - May 404 or redirect incorrectly on different configurations **Required Fix:** ```typescript // Get from WooNooW config const basePath = (window as any).woonoowCustomer?.basePath || ''; const shopPath = basePath + '/shop'; // or wc_get_page_id('shop') permalink ``` ### High (Important) #### 3. No Cookie Capture on Block Checkout **Location:** Backend - AffiliateTracker.php **Severity:** High **Issue:** `capture_referral_link()` only fires on `init`. Block-based checkout may: - Load via AJAX without full page reload - Use Store API without triggering WordPress `init` - Miss the `?ref=` parameter entirely **Impact:** Some block checkout flows may lose referral attribution **Required Fix:** Referral attribution must remain reliable across all WooCommerce checkout variants and navigation patterns. The persistence mechanism (cookie, localStorage, server-side session) is secondary to ensuring the `?ref=` parameter is captured and associated with the order regardless of how the customer navigates to checkout. ```php // AffiliateTracker.php - Ensure referral is captured before order creation // Option 1: Check for ref in session/storage on order hooks // Option 2: Ensure PHP session captures ref via frontend AJAX call // Option 3: Store ref in order meta during checkout for guaranteed attribution ``` #### 4. Self-Referral Block Has No Override **Location:** Backend - AffiliateTracker.php:133-135 **Severity:** High **Issue:** ```php if ((int)$order->get_user_id() === (int)$affiliate->user_id) { return; // Blocks all self-referrals } ``` No admin option to: - Allow self-referrals for testing - Whitelist specific affiliate-customer pairs - Override after verification **Impact:** Cannot test with same account (must use different customer account) #### 5. No Per-Affiliate Commission Override **Location:** Backend + Database **Severity:** High **Issue:** - All affiliates use global `woonoow_affiliate_default_rate` setting - No ability to set custom rate per affiliate - No ability to override for special cases **Impact:** Limited merchant flexibility for VIP affiliates ### Medium (Should Fix) #### 6. No Referral Filtering in Admin **Location:** Admin SPA - Referrals.tsx **Severity:** Medium **Issue:** AffiliatesReferrals shows ALL referrals. No: - Filter by affiliate - Filter by date range - Filter by status - Filter by order **Impact:** Hard to track specific affiliate performance #### 7. Affiliate Cannot See Referral Details **Location:** Customer SPA - AffiliateDashboard.tsx **Severity:** Medium **Issue:** Dashboard shows order ID and commission only. No: - Order date - Product details - Commission status explanation - When payment will be released **Impact:** Low trust due to lack of transparency #### 8. Commission Based on Subtotal Only **Location:** Backend - AffiliateTracker.php:139-144 **Severity:** Medium **Issue:** ```php $subtotal = (float)$order->get_subtotal(); $commission_amount = ($subtotal * $commission_rate) / 100; ``` - Does not account for taxes - Does not account for shipping - Does not account for discounts **Impact:** Affiliates may dispute calculated amounts (requires clear documentation) ### Low (Nice to Have) #### 9. No Admin Dashboard Metrics **Location:** Admin SPA **Severity:** Low **Issue:** No summary cards showing: - Total affiliates count - Active vs pending breakdown - Total commission paid - Conversion rate **Impact:** Hard to assess program health at a glance #### 10. No Email Template Customization **Location:** Backend - Email System **Severity:** Low **Issue:** - Templates hardcoded in DefaultTemplates.php - No admin settings for customization - No branding options **Impact:** Limited to default styling --- ## Opportunities ### Priority 1: Operational Completeness (Must-Have) These features make the affiliate module operationally functional — without them, merchants cannot run a real affiliate program. #### 1. Complete Payout System **Status:** Placeholder (0% implemented) **Scope:** Backend + Admin SPA Payout is not a secondary detail — it is the final proof that the system works. Merchants need to be able to: - [ ] Calculate payable balance per affiliate (`total_earnings - paid_earnings`) - [ ] View payout history per affiliate - [ ] Create payouts with amount input (not auto-all) - [ ] Support multiple payout methods (Bank Transfer, PayPal, Store Credit) - [ ] Mark payouts as pending → completed - [ ] Send payout notification email to affiliate **API required:** - `GET /admin/affiliates/payouts` - List all payouts - `GET /admin/affiliates/{id}/balance` - Get payable balance - `POST /admin/affiliates/{id}/payout` - Create payout #### 2. Attribution Reliability & Tracking Rules **Status:** Partial (works for most cases) **Scope:** Backend Silent attribution failures damage trust quickly. Need to ensure: - [ ] Referral link adapts to site's actual SPA structure (not hardcoded `/shop`) - [ ] Cookie capture works for AJAX/block checkout flows (not just page reload) - [ ] Referral codes are case-insensitive during lookup - [ ] Invalid/expired referral codes handled gracefully (no errors) **Technical approach:** ```php // Dynamic referral link generation $shop_page = get_permalink(wc_get_page_id('shop')); $referral_link = add_query_arg('ref', $referral_code, $shop_page); ``` #### 3. Commission Management & Overrides **Status:** Global rate only (no per-affiliate override) **Scope:** Backend + Admin SPA Merchants need granular control: - [ ] Set custom commission rate per affiliate (override global default) - [ ] Manually adjust commission amount per referral - [ ] Set custom holding period per affiliate - [ ] Mark referral as "Manual Adjustment" with audit trail - [ ] Commission calculation rules (subtotal vs total, include/exclude tax, etc.) **Database consideration:** Add `custom_commission_rate` column to `wp_woonoow_affiliates` (nullable, uses default if null). --- ### Priority 2: Transparency & Trust (Should-Have) These features build trust with both merchants and affiliates through visibility and control. #### 4. Admin Performance Dashboard **Status:** Basic list only (no metrics) **Scope:** Admin SPA Merchants need to assess program health: - [ ] Summary cards: Total Affiliates, Active vs Pending, Total Commission (approved), Unpaid Commission - [ ] Conversion rate: Applications vs Approved - [ ] Top performing affiliates - [ ] Monthly earnings trend chart - [ ] Export to CSV/Excel #### 5. Customer Dashboard Transparency **Status:** Basic (earnings + recent referrals) **Scope:** Customer SPA Affiliates need to trust the system: - [ ] Referral status breakdown (pending approval vs approved vs paid) - [ ] "When will I get paid?" indicator (holding period countdown) - [ ] Referral detail view: which order, what commission, current status - [ ] Payout history view (coming when payout system is complete) **Example referral detail card:** ``` Order #476 • May 30, 2026 Commission: Rp19.900 Status: Pending (3 days until approval) Product: Design Mockup Bundle ``` #### 6. Trust & Compliance Layer **Status:** Basic self-referral check only **Scope:** Backend (core trust layer, not nice-to-have) Affiliate systems are always exposed to abuse. Define anti-fraud rules early: - [ ] Self-referral block with admin exception/override - [ ] Suspicious order flagging (unusually high value from new customer) - [ ] Rate limiting on referral code generation per IP - [ ] Audit log for manual commission adjustments - [ ] Clear commission rules documentation (what's included/excluded) **Database consideration:** Add `fraud_score` column to `wp_woonoow_referrals` for future ML-based scoring. --- ### Priority 3: Scalability Features (Nice-to-Have) These enable growth but are not blocking for initial launch. #### 7. Enhanced Referral Tracking **Scope:** Backend - [ ] Track referral source (email, social, direct, paid) - [ ] Store click data (IP, user agent, timestamp) - [ ] UTM parameter capture - [ ] Cross-device tracking (logged-in users) #### 8. Referral Filtering & Search **Scope:** Admin SPA - [ ] Filter by affiliate - [ ] Filter by date range - [ ] Filter by status (pending/approved/rejected) - [ ] Filter by order ID - [ ] Search by customer email (anonymized display) #### 9. Affiliate Self-Service Portal **Scope:** Customer SPA - [ ] Update payment details (bank account, PayPal) - [ ] View payout history - [ ] Download referral reports (CSV) - [ ] Tax document download (1099 placeholder) --- ### Future Roadmap (Post-MVP) These are growth features, not near-term priorities. Merchants care about correctness first. #### Multi-Tier Commissions - Volume-based tiers (10% for 0-10 referrals, 15% for 11-50, etc.) - Requires: Tier configuration UI, recalculation on new referral #### Integration Ecosystem - WooCommerce Currency Switcher compatibility - Export to accounting software (Xero, QuickBooks) - Zapier/Make integrations for automation #### Gamification - Achievement badges (First Referral, Top Performer) - Leaderboards - Referral contests with goals and rewards #### MLM Structure - Multi-level marketing (not recommended for most WooCommerce setups) - Keep lower priority unless specifically requested --- ## Recommendations ### This Sprint (Operational Core) | Task | Priority | Effort | Impact | |------|----------|--------|--------| | Fix referral link path (dynamic) | Critical | Low | Reliability | | Implement payout balance calculation | Critical | Medium | Completeness | | Add payout creation UI | Critical | Medium | Completeness | | Add self-referral admin override | High | Low | Trust | | Add referral filtering in admin | Medium | Medium | Usability | ### Next Sprint (Transparency) | Task | Priority | Effort | Impact | |------|----------|--------|--------| | Admin performance dashboard | High | Medium | Visibility | | Customer referral detail view | High | Medium | Trust | | Per-affiliate commission override | High | Medium | Control | | Commission rules configuration | Medium | High | Flexibility | ### Future (Growth) - UTM/source tracking - Affiliate self-service portal - Integration ecosystem - Multi-tier commissions --- ## File Checklist | Path | Type | Description | |------|------|-------------| | `/includes/Modules/Affiliate/AffiliateModule.php` | PHP | Module bootstrap | | `/includes/Modules/Affiliate/AffiliateManager.php` | PHP | DB tables | | `/includes/Modules/Affiliate/AffiliateTracker.php` | PHP | Tracking logic | | `/includes/Modules/Affiliate/AffiliateLifecycle.php` | PHP | Order lifecycle | | `/includes/Modules/Affiliate/AffiliateSettings.php` | PHP | Settings schema | | `/includes/Api/Controllers/AffiliateAdminController.php` | PHP | Admin API | | `/includes/Api/Controllers/AffiliateCustomerController.php` | PHP | Customer API | | `/admin-spa/src/routes/Marketing/Affiliates/index.tsx` | TSX | Admin layout | | `/admin-spa/src/routes/Marketing/Affiliates/List.tsx` | TSX | Affiliate list | | `/admin-spa/src/routes/Marketing/Affiliates/Referrals.tsx` | TSX | Referral list | | `/admin-spa/src/routes/Marketing/Affiliates/Payouts.tsx` | TSX | Payouts (placeholder) | | `/admin-spa/src/routes/Orders/Detail.tsx` | TSX | Order affiliate info | | `/customer-spa/src/pages/Account/AffiliateDashboard.tsx` | TSX | Customer dashboard | | `/customer-spa/src/pages/Account/index.tsx` | TSX | Account routes | | `/customer-spa/src/pages/Account/components/AccountLayout.tsx` | TSX | Menu integration | --- *Report Version: 1.2* *Last Updated: 2026-05-31* *Generated by: Claude Code* *Review Status: Final - Reviewed and validated*