Install
This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.
Install straight from GitHub with WP-CLI:
wp plugin install https://github.com/sirdadfar/woo-affiliate-pro/archive/refs/heads/main.zipAn affiliate program for WooCommerce with a Persian dashboard, per-affiliate referral links, per-category commission rates, integer money math, and manual payout management — built for Iranian stores that want to grow through affiliates without spreadsheets and direct messages.
🇮🇷 توضیحات فارسی · Security · Changelog
What problem this solves
Many WooCommerce stores run affiliate programs with a spreadsheet and direct messages: codes are created by hand, commissions are recalculated manually, and payout history lives in a separate file. That stops scaling once there are more than a handful of affiliates, and a one-rial discrepancy is enough to lose trust.
This plugin keeps attribution, calculation, lifecycle state, and payout requests inside WooCommerce. Money is calculated in integer minor units so floating-point drift cannot accumulate across thousands of orders. Commission records are never deleted; they change state, so the financial history stays auditable.
Features
Attribution and tracking
- Per-affiliate link with
?ref=CODEand an 8-character code from the restricted[A-Z0-9]alphabet. - Referral cookie for 1–365 days (default 30),
HttpOnly,SameSite=Lax, andSecureon HTTPS. - Last click wins; an invalid code never replaces an existing valid one.
- Attribution is written to the order when the order is created, not when it completes, so delayed payments, bank transfers, and manual approval do not lose the referrer.
- At most one click is recorded per visitor every 60 seconds: refreshes do not inflate the stats, while two different visitors clicking at the same time are both counted (the lock key is affiliate id + a hash of IP and User-Agent).
- Self-referral protection by WordPress user ID and billing email.
Commission calculation
- Percentage rate per affiliate plus per-category overrides.
- Product and category exclusions.
- Per-order commission cap, stored as an explicit negative adjustment line so the sum of the breakdown always equals the final amount.
- Base is the line total after discount; tax and shipping are opt-in.
- Integer minor-unit arithmetic and half-up rounding; no
floaton the money path. - Currencies with 0–4 decimal places, driven by
wc_get_price_decimals().
Commission lifecycle
pendingwhen the order is created.approvedwhen the order reachescompletedorprocessing(configurable).paidafter the payout is settled.reversedon cancellation or full refund; the record is kept.rejectedfor manual rejection by an administrator.- Allowed transitions are enforced in the domain layer; jumping from
pendingtopaidis rejected.
Affiliate dashboard
[wap_dashboard]: available balance, total approved commission, clicks in the last 30 days, and total clicks.- Referral link with a copy button and select-on-focus behavior.
- Commission and payout tables that turn into label/value cards below 760 px.
- Payout request form with server-side validation and per-field error messages.
[wap_join]: registration form that preserves submitted values after an error.
Administration
- Affiliate list with status filters, counts, and pagination.
- Commission list with status filters, totals, and HPOS-safe order links.
- Payout list with payout destination, reference number input, and status transitions.
- Settings for rates, exclusions, caps, minimum payout, and uninstall data deletion.
- POST-Redirect-GET after every mutation, so refreshing the page cannot repeat a payout.
Infrastructure
- HPOS (WooCommerce custom order tables) compatibility declared; all order access goes through the public order API.
- Block checkout (Store API) is supported alongside the classic checkout; attribution is written on the order in both flows.
- REST API for mobile apps and external panels.
- WP-Cron job that prunes old clicks and recovers missed commission approvals.
- A bespoke design system (CSS tokens, glass surfaces, one gold accent, dark mode via
prefers-color-scheme) with Vazirmatn bundled in the plugin — no Google Fonts or CDN request at all. - No runtime dependencies beyond PHP and WooCommerce, no build step, and no CDN JavaScript.
Requirements
| Item | Version |
|---|---|
| PHP | 7.4 or newer (CI covers up to 8.3) |
| WordPress | 6.0 or newer |
| WooCommerce | 7.0 or newer |
| Composer | Only for development dependencies and running tests |
The plugin header claims compatibility with WooCommerce up to 9.4. That claim has not been verified on a live WordPress/WooCommerce installation; only public API contracts were reviewed. Run a test order on staging before production use.
Installation and setup
Install from source
git clone https://github.com/sirdadfar/woo-affiliate-pro.git
cd woo-affiliate-pro
composer install --no-dev
Place the directory at wp-content/plugins/woo-affiliate-pro and activate it in WordPress. When installed as a zip without Composer, the plugin falls back to a bundled lightweight autoloader and still works.
First run
-
Activate WooCommerce. Without it, the plugin shows an admin notice and does nothing.
-
Create two pages.
Page Shortcode Purpose Affiliate dashboard [wap_dashboard]Affiliate panel Affiliate signup [wap_join]Registration form -
Open “Affiliate → Settings” and set the default rate, minimum payout, and other options.
-
Create a test account, register through
[wap_join], and open the referral link in a separate browser or private window. -
Place a test order and follow the commission through “Affiliate → Commissions”.
The installer creates these tables using the WordPress table prefix:
| Table | Purpose |
|---|---|
{prefix}wap_affiliates |
Affiliates, codes, rates, payout details |
{prefix}wap_clicks |
Referral clicks with hashed IPs |
{prefix}wap_commissions |
One commission row per order and affiliate |
{prefix}wap_payouts |
Payout requests and reference numbers |
Configuration
Settings are stored in a single WordPress option named wap_settings. Monetary values (min_payout, max_commission) are stored in the smallest currency unit; for IRR without decimals, 100000 means 100,000 rials.
| Key | Default | Meaning |
|---|---|---|
cookie_days |
30 |
Referral cookie lifetime, 1–365 days |
default_rate_bp |
1000 |
Default rate in basis points; 1000 means 10% |
include_shipping |
false |
Include shipping in the commission base |
include_tax |
false |
Include tax in the commission base |
category_rates |
[] |
Map of category_id => basis_points |
exclude_products |
'' |
Comma-separated excluded product IDs |
exclude_categories |
'' |
Comma-separated excluded category IDs |
max_commission |
0 |
Per-order commission cap; 0 means no cap |
min_payout |
100000 |
Minimum payout amount |
approve_on |
completed |
Approve on completed or processing |
auto_approve |
true |
Activate new affiliates without manual review |
delete_data_on_uninstall |
false |
Drop tables and settings when the plugin is deleted |
Extensibility filter
| Filter | Default | Purpose |
|---|---|---|
wap_click_retention_days |
180 |
Click retention; the final value is clamped to 1–3650 days |
Usage
Affiliate journey
- The customer signs in to a WordPress account.
- On the
[wap_join]page they enter a name, a mobile number matching09xxxxxxxxx, and a payout method. - With auto-approval enabled the account becomes active immediately; otherwise it stays
pendinguntil an administrator approves it. [wap_dashboard]shows the referral link, click stats, balance, and history.- Once the balance reaches the minimum payout, the payout form becomes available.
- The request appears in the admin payout list, and its status is reflected back in the affiliate panel.
Administrator journey
- Affiliates: approve, activate, disable, or reject a request.
- Commissions: review base and status; approve manually or reverse.
- Payouts: check the stored destination against the affiliate record, record a reference number, and move the request to
processing,paid, orrejected. - Settings: change rates and rules. Changes affect future commissions and do not rewrite history.
REST API
| Route | Method | Access | Purpose |
|---|---|---|---|
/wp-json/wap/v1/me |
GET | Logged-in user | Code, status, referral URL, and balance |
/wp-json/wap/v1/payouts |
POST | Logged-in user | Create a payout request with amount (integer minor units) |
/wp-json/wap/v1/affiliates |
GET | manage_woocommerce |
Paginated affiliate list |
Authentication uses WordPress cookie plus nonce, or an Application Password. The write route has its own rate limit and concurrency lock.
Security
- Every PHP file starts with
defined( 'ABSPATH' ) || exit;. - Every query with variables uses
$wpdb->prepare(), and table names come from$wpdb->prefix. - Every output is escaped with
esc_html,esc_attr,esc_url,esc_textarea, orwp_kses_post. - Every state-changing admin action checks both
current_user_canand its own nonce; a failed nonce returns 403. - Every REST route has a real
permission_callback; no write route is public. - Referral codes are strictly validated; `