Skip to main content

Vendor Management

Overview​

The Vendor module turns a single store into a marketplace. Vendors own products, an order is split into per-vendor lines when it is placed, commission is calculated when the order completes, and the balance owed is settled through payouts an administrator opens and marks complete.

Each vendor gets a public store page at /vendor/{slug}/, a Vendor Dashboard page in My Account, and a "sold by" line on their products. Applications can be taken through a shortcode and approved by an administrator.

It is for stores selling other people's stock. Money movement is recorded, not executed: the module opens a payout, records a transaction reference and marks it complete or failed — no payment provider ships with it.

Availability​

ItemValue
Module keyvendor_management
TierPremium
Entitlement keyvendor_management
Admin tabvendors, under Operations
Enabled optionaiowc_module_enabled_vendor_management (off until turned on)
REST namespaceaiowc/v1

Enabling the module creates the five tables below, seeds the defaults, adds the aiowc_vendor role, schedules both jobs and flags the rewrite rules to be flushed on the next init. Disabling it unschedules the jobs.

The vendor role​

onEnable() adds an aiowc_vendor WordPress role with read, edit_products, delete_products and upload_files, and explicitly without publish_products, edit_posts, delete_posts or view_woocommerce_reports. A vendor can therefore draft and edit products but not publish them, which is what makes approval meaningful.

Settings​

Stored in the bundled option row aiowc_vm_settings; legacy per-key options are migrated on first read.

Stored keyDefaultMeaning
enable_registrationtrueAccept vendor applications.
registration_approvaltrueA new vendor lands as pending and must be approved.
default_commission_rate10Commission used when a vendor or product has no rate of its own.
commission_typepercentagepercentage, fixed or tiered.
minimum_payout_amount50A vendor below this balance is skipped by the payout cycle.
payout_schedulemonthlyweekly, biweekly or monthly — when the payout job considers itself due.
auto_approve_productsfalseRead when a product is assigned, but both branches produce the same result — see Known gaps.
vendor_dashboard_page0Page id holding the dashboard shortcode.
enable_vendor_ratingstrueStored, but nothing writes a rating — see Known gaps.
show_vendor_on_producttrueDraw the "sold by" line on the product page.
vendor_store_page_enabledtrueServe the /vendor/{slug}/ store archive.

The last two are read once, when hooks are registered: turning either off means the matching hooks are never attached.

Admin screen​

The Multi-Vendor Management tab is one screen with two tables.

Vendors lists every vendor with their store, commission rate, pending earnings and status, and offers approve, suspend, open-a-payout and remove actions, plus an Add vendor dialogue taking an email, contact name, store name and an optional commission rate.

Pending payouts lists open payouts and takes a transaction reference to mark one complete, or marks it failed.

Order flow​

  1. woocommerce_checkout_order_processed — the order is split into one vendor-order line per item that belongs to a vendor.
  2. woocommerce_order_status_completed — the split is re-run (it is idempotent) and each pending line has its commission calculated: the commission amount and the vendor's earning are written onto the line and into the commission table, and the vendor's totals are updated.
  3. Reconciliation — the hourly job walks up to 100 lines still marked pending, looks up each order, and either calculates it (order completed) or voids it (order cancelled, refunded, failed or trashed). Voiding reverses earnings already credited and marks the lines cancelled, skipping anything already paid out.

Voiding happens only through that hourly pass. No hook fires on woocommerce_order_status_cancelled or _refunded, so a cancelled order's commission is reversed at the next reconciliation rather than immediately.

Payouts​

createPayout() opens a payout for a vendor's unpaid balance. runPayoutCycle() walks the vendors whose balance is at or above minimum_payout_amount, skipping any vendor that already has a pending payout, and opens one each. A payout is then completed with a transaction reference, or failed with a note; both record the acting administrator and the time.

The payout job is scheduled daily but only acts when payout_schedule says it is due, comparing against the last run in the site's timezone.

REST API endpoints​

All routes are on aiowc/v1. The vendor CRUD routes answer bare rather than in the envelope; the rest use { success, data, message }.

MethodPathPurposePermissionRequired args
GET/vendorsList vendors; filters status, search, page, per_page.manage_woocommerce–
POST/vendorsCreate a vendor.manage_woocommercestore_name
GET/vendors/{id}Read one vendor.manage_woocommerceid
PUT / PATCH / POST/vendors/{id}Update a vendor.manage_woocommerceid
DELETE/vendors/{id}Delete a vendor.manage_woocommerceid
POST/vendors/{id}/statusSet a vendor's status — this is how an application is approved or suspended.manage_woocommerceid, status
GET/vendors/{id}/productsProducts assigned to a vendor.manage_woocommerceid
POST/vendors/{id}/productsAssign a product, optionally with its own commission rate and type.manage_woocommerceid, product_id
DELETE/vendors/{id}/products/{product_id}Unassign a product.manage_woocommerceid, product_id
GET/vendors/{id}/ordersA vendor's order lines.manage_woocommerceid
GET/vendors/{id}/payoutsA vendor's payouts.manage_woocommerceid
POST/vendors/{id}/payoutsOpen a payout for a vendor.manage_woocommerceid
GET/vendors/payoutsAll payouts; filters status, vendor_id, page, per_page.manage_woocommerce–
POST/vendors/payouts/{id}/completeMark a payout complete with a transaction_id.manage_woocommerceid
POST/vendors/payouts/{id}/failMark a payout failed with notes.manage_woocommerceid
GET/vendors/settingsRead the settings above.manage_woocommerce–
PUT / PATCH / POST/vendors/settingsUpdate the settings above.manage_woocommerce–
GET/vendors/meThe signed-in vendor's own dashboard data.Signed-in user–

WooCommerce integration​

HookPriorityWhat the module does
woocommerce_checkout_order_processed10Splits the order into per-vendor lines.
woocommerce_order_status_completed10Calculates commission for that order's pending lines.
woocommerce_single_product_summary7Draws the "sold by" line (when show_vendor_on_product is on).
woocommerce_account_menu_items10Adds Vendor Dashboard to My Account.
woocommerce_account_vendor-dashboard_endpoint10Renders the dashboard in My Account.
template_redirect10Handles a submitted vendor registration.
pre_get_posts / posts_join10Scopes the /vendor/{slug}/ archive to that vendor's products.
woocommerce_archive_description10Draws the store header on that archive.
init10Registers the account endpoint and the two /vendor/{slug}/ rewrite rules.

Shortcodes

ShortcodeRenders
[empora_vendor_dashboard]The signed-in vendor's dashboard.
[empora_vendor_register]The vendor application form.

Database schema​

TableHolds
{prefix}aiowc_vendorsThe vendor: user id, store name and slug, description, logo and banner, commission rate and type, status, running sales and earnings totals, rating, payment method and details, address, phone, social links. Unique on user id and on store slug.
{prefix}aiowc_vendor_productsWhich products belong to which vendor, with an optional per-product commission.
{prefix}aiowc_vendor_ordersOne line per vendor per order item: quantity, line total, commission amount, vendor earning, status, commission status, payout id.
{prefix}aiowc_vendor_payoutsPayouts: amount, method, details, transaction id, status, notes, who processed it and when.
{prefix}aiowc_vendor_commissionsThe commission record behind each line: rate, type, amount, earning, status, payout id, calculated and paid times.

Background jobs​

HookIntervalWork
aiowc_vendor_commissions_reconcilehourlyCalculates or voids up to 100 pending order lines the live hooks missed.
aiowc_vendor_payouts_processdailyRuns the payout cycle when payout_schedule says it is due, and records the run time.

Action hooks for integrators​

HookFired when
aiowc_vendor_registeredA vendor record is created, with its status.
aiowc_vendor_status_changedA vendor moves between statuses.
aiowc_vendor_commission_calculatedA line's commission is worked out.
aiowc_vendor_payout_createdA payout is opened.
aiowc_vendor_payout_completedA payout is marked complete.
aiowc_vendor_payout_failedA payout is marked failed.

Entitlement limits​

vendor_management is an on/off grant with no cap on vendors, products or payouts. The numeric limits are store settings and constants: the minimum payout amount, the payout schedule, and the 100-line reconciliation batch.

Health check​

The module reports a warning when its tables are missing or WooCommerce is inactive. Otherwise it reports that it is functioning normally.

Known gaps​

  • No payment is executed. Completing a payout records a transaction reference an administrator supplies; nothing is sent to a payment provider.
  • commission_type accepts tiered, and the vendor and product records carry a type each, but there is no tier table — a tiered rate has nowhere to define its bands.
  • There is no admin screen for assigning products to vendors, or for browsing a vendor's order lines; both are REST-only.
  • Vendor ratings are never written. enable_vendor_ratings is a setting, the vendor row has rating_average and rating_count, and VendorRepository::updateRating() exists — but nothing calls it, and no route or screen collects a rating.
  • auto_approve_products has no effect. In VendorService::assignProduct() both branches of its ternary produce 'active', so an assigned product is active either way (includes/Modules/VendorManagement/Service/VendorService.php:305).