21 KiB
Affiliate Module - Implementation Report
Document Version: 1.0 Date: 2026-05-31 Module: WooNooW Affiliate Program
Table of Contents
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
inithook; may miss AJAX-based checkout flows - Dynamic referral link — Current implementation assumes
/shoppath; 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
- Payout workflow — Cannot pay affiliates (blocking)
- Per-affiliate commission override — No custom rates (high priority)
- Self-referral override — No admin whitelist (high priority)
- 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<id>\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:
// 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:
// 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:
// 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.
// 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:
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_ratesetting - 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:
$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 payoutsGET /admin/affiliates/{id}/balance- Get payable balancePOST /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:
// 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