= 3.8.4 =
* Added (PRO): optionally deduct each WooCommerce charge's exact Stripe processing fee from its connected-account transfers. The fee is allocated proportionally across every planned vendor leg in settlement-currency minor units, saved before any transfer is sent, and reused for retries and refunds. The setting is off by default, never changes existing or in-progress orders, and does not affect FluentCart.
* Added (PRO): optional sequential global product splits for WooCommerce orders. Fixed product-level transfers are subtracted first, then global rows use the remaining merchandise amount from top to bottom. Product percentages and existing tax, shipping, fee, and add-on calculations are unchanged; existing gross behavior remains the default.
* Added (PRO): append one connected-account recipient to selected WooCommerce products and displayed variations from the Bulk Editor. Products without that recipient get one new row; an identical row is left alone; one conflicting row can be merged or skipped; multiple matching rows can only be skipped. All unrelated rows remain unchanged, and a preview shows conflicts and exact row counts before saving.
* Added (PRO): optional identity-bound generic Stripe Connect links for WCFM vendors. When enabled, a signed-in WCFM vendor is routed through the existing WCFM Stripe Payouts flow so the returned Test or Live account is bound to that exact site, user, and mode. Existing generic links remain unchanged by default.
* Added (PRO, WCFM): a "Default vendor share for auto-linked products (%)" setting on the WCFM integration card, with a matching spp_wcfm_autolink_default_percent filter. Previously a newly auto-linked vendor product was always assigned 100% unless a legacy global percentage option existed, so the platform kept nothing on that product; the default is unchanged, the card now warns when it applies, and existing product links are never rewritten.
* Fixed: "Retry Split Pay Transfers" now records an order note when a site gate declines the retry, instead of returning silently with no trace of the click.
* Fixed: Global Transfer Settings could not be saved on sites upgraded to 3.8.4 (the form reported that its previous settings were restored). WordPress skips creating an option row when a registered default already equals the value being written, so the new WCFM identity-bound toggle never existed and the save's exact readback failed; option writes and the recovery-journal restore now create the row when it is missing, and the exact reason of any rolled-back save is written to WooCommerce > Status > Logs (source: split-pay).
* Improved: rarely-needed transfer options (sequential global splits, Stripe-fee allocation, WCFM identity-bound Connect links) are grouped under a collapsible "Advanced transfer options" section on Global Transfer Settings. Values and behavior are unchanged.
* Added: exact, site-scoped Test/Live account pairing for new vendor onboarding and administrator-confirmed pairs. Existing saved account IDs keep the 3.8.3 email, then name, then as-saved fallback unless an administrator confirms that exact pair or replaces a mode's key with a key for a different verified Stripe platform. The WCFM opt-in is isolated to WCFM vendor identity and cannot change unrelated Global or FluentCart routing. Strict-mode conflicts stop before any transfer is created.
* Compat: unexpired Connect links created by 3.8.3 remain valid until their signed expiry. New links are also bound to the WordPress site that created them, so they cannot be replayed on another site sharing the same salts.
* Compat: a normal uninstall that retains account and financial records now also retains the signed proof keys and site-scoped Connect identity policy needed to authenticate those records after reinstall. The explicit destructive-data option removes that bundle only when Split Pay verifies a stable product-settings generation with no recovery journal; otherwise recovery-owned state is retained for a safe reinstall. The in-flight onboarding generation token is always reset.
* Compat: while Split Pay 3.8.4 or newer is active, standard WordPress Update now/auto-update flows reject Split Pay packages older than 3.8.4, or packages whose main plugin file cannot be verified, before installed files are replaced. Manual FTP/file replacement, uploaded-ZIP overwrite/force-install flows, and WP-CLI commands that skip loading Split Pay are not covered.
* Fixed: connected-account refresh keeps the 3.8.3 credential order, using the first key that returns a complete mode catalog and trying lower-priority keys only when an earlier catalog is unavailable or incomplete. Reset verifies one complete catalog for every configured mode before clearing local rows. After a mode is explicitly moved to a different verified Stripe platform, refresh and reset also require its potentially usable credentials to resolve to that platform; conflicts leave rows and settings unchanged. Rejected onboarding attempts are ignored, Stripe's Dashboard display name is used when available, and manually added accounts require complete mode-specific catalog verification.
* Fixed: product, variation, Bulk Editor (including FluentCart rows), and Global Transfer Settings saves now use a verified recovery journal. Partial or interrupted saves restore the prior state when possible; an unresolved routing generation stops WooCommerce transfer preparation instead of mixing configurations.
* Fixed (WCFM/Dokan): newly auto-linked product routes now carry signed ownership proof. Proof-bearing routes are removed on disconnect only when the exact plugin-owned vendor/account tuple verifies; manual routes are not adopted, while legacy unmarked WCFM rows retain 3.8.3 disconnect behavior.
* Fixed: the first WooCommerce transfer retry now uses a fresh Stripe idempotency attempt, so a previously failed transfer is actually tried again while already-successful transfers remain protected from duplicates.
* Fixed: FluentCart mixed-transfer retries now keep a signed, per-transfer plan. A transfer already proven complete is not sent again; a clearly rejected transfer alone gets a fresh key; and an uncertain or older result is reconciled against the complete Stripe transfer inventory before any new transfer is allowed. Missing, conflicting, or incomplete evidence stops safely for review.
* Fixed: Vendor Onboarding settings now recognize a usable platform key supplied by Payment Plugins or FluentCart instead of requiring the official WooCommerce Stripe settings array.
* Fixed: readiness classifies misplaced keys by their actual Test/Live prefix, and official WooCommerce Stripe refunds accept that gateway's matching same-mode native key during the final rotation check.
* Clarified: gateway key and read-only webhook-check labels now describe their exact key source, and Dokan reconcile mode is labeled as the order-note-only action it performs.
* Clarified: delayed transfers released after a charge settles require enough available platform balance; automatic payouts can otherwise make the delayed transfer fail.

= 3.8.3 =
* Fixed: existing sites upgrading from 3.8.0/3.8.1 keep an interactive settings tab — the verified platform identity is backfilled on upgrade from the saved platform key (the same read-only Stripe check "Run readiness check" performs), and "Run readiness check" now persists a verified identity instead of only reporting it. Previously the Global Transfer Settings tab could stay grayed out after the upgrade until the key was saved again.
* Fixed: re-activating the plugin after an uninstall that kept your data no longer logs "Duplicate column name" database notices; existing table columns are detected before each schema step runs.
* Compat: WordPress 7.1 compatibility (Tested up to: 7.1).
* Note: 3.8.3 also contains everything listed under 3.8.2 below — the 3.8.2 candidate was certified but never published.

= 3.8.2 =
* Fixed: new WooCommerce products with an untouched Split Pay row no longer emit PHP warnings, and blank product rows continue to use the global product transfer.
* Security: Product Add-Ons recipient settings now save only from an authorized group edit; autosaves, unrelated posts, missing fields, and invalid nonces leave the saved recipient unchanged.
* Improved: background migrations now use the available public Action Scheduler APIs. The verified minimums are WordPress 6.1, WooCommerce 7.9, and PHP 7.4; WooCommerce 10.9 is also verified.
* Added (PRO): field-value routing — route a product's transfer to a different connected account based on the value the customer selected for a product field (e.g. WooCommerce Custom Fields, Advanced Product Fields) or a checkout/order-meta field. Configure the field identifier and value → account rules on the new Field-value routing card under Global Transfer Settings; split percentages and amounts are never changed, and values without a rule keep the product's configured account.
* Fixed: tax routed to vendors from coupon-discounted WooCommerce orders now uses WooCommerce's post-discount line tax, preventing the pre-discount tax from inflating a split.
* Fixed: WooCommerce refunds for orders settled in a different currency now size transfer reversals in the settlement currency's minor units.
* Fixed: cross-currency transfer notes, vendor emails, failed-payout logs, and Transfers rows now show settlement amounts in the correct currency and minor-unit scale. Mixed transfer batches also remain visibly failed when another recipient was paid successfully.
* Fixed: FluentCart products whose saved recipient slots are all blank remain eligible for the configured global split instead of silently paying no recipient.
* Fixed: removing the final connected account from a product or variation now stays removed after Update and reload instead of restoring the previous recipient.
* Fixed: connected-account database upgrades now reconcile and verify the current schema without rewriting existing merchant routing rows or marking a failed upgrade complete.
* Fixed: product-settings recovery now restores only one unambiguous, positive WooCommerce product transfer. Legacy, global, add-on, FluentCart, and ambiguous rows can no longer become product routes, including fixed-zero routes that suppress a valid global split.
* Fixed: WordPress.org language packs now use the plugin directory's registered text domain so translations can load correctly.
* Fixed: unavailable multi-account preview controls are now non-interactive in Free and expired-license views.
* Improved: Connect Status, settings, integrations, and onboarding now use one consistent readiness check. Product-only routing counts as configured, incomplete recipients remain visible with clear warnings, and readiness views no longer contact Stripe.
* Fixed: Stripe platform keys are now identity- and permission-checked before either settings screen can replace a saved key. Rejected keys and provider errors keep the previous key and state; failed readbacks restore the previous snapshot or show a blocking warning when restoration cannot be confirmed. Key changes, account sync/reset actions, and active transfer/refund work now share a per-site lock so one request cannot mix two generations of platform state. Secret fields now use blank password inputs with accessible reveal controls and clear typed values on every terminal path. Repeated Save Changes clicks can no longer race duplicate settings writes.
* Fixed: fee-routing rules now save through the Global Transfer Settings page's single native Save Changes action instead of a separate button that could silently leave the rules unsaved.
* Fixed: fixed-amount shipping splits on product variations remain effective across 3.8.1 upgrades. Split Pay now keeps the legacy and modern variation amount keys synchronized, while preserving existing 3.8.1 values until each variation is saved again.
* Fixed: FluentCart transfers now use Stripe's settlement currency for cross-currency charges, keep global shipping independent from product routing, and retain charge-bound idempotency state through retries. Partial refunds use the current refund amount, and unexpected failures remain safely retryable.
* Fixed: WooCommerce retries now match already-paid global, product, shipping, and add-on legs across the complete plan before sending new money. Valid same-recipient retries no longer trip a false divergence stop, while a genuinely changed payout remains fail-closed.
* Fixed: transfer-log amounts now preserve three-decimal currencies such as KWD without truncation. The database upgrade widens all eight money columns in place and verifies the resulting definitions before enabling debt-ledger transactions.
* Fixed: expired-license and stale admin forms no longer erase stored fixed, shipping, or product-routing values that the browser could not submit. FluentCart bulk edits also preserve fixed shipping when that field was not submitted.
* Fixed: status/readiness indicators, the Transfers mode switcher, and the Bulk Editor category search now expose accessible contrast, state, and labels in wp-admin.
* Security: legacy privileged AJAX actions now return HTTP 403 for insufficient permissions and reject invalid nonces explicitly instead of ending with an ambiguous HTTP 200 response.
* Security: successful transfer emails no longer write full email and order objects to the PHP debug log.
* Fixed: uninstall now removes every Split Pay option and ephemeral dismissal. Destructive cleanup also removes each opted-in site's financial tables; shared Split Pay vendor metadata is removed on single-site installs or when every multisite site opts in. Product-level split values remain attached to products.
* Fixed: "Retry Split Pay Transfers" was blocked on every store running 3.8.1 with "the amount already transferred for this order's charge could not be verified with Stripe just now." The retry's double-pay safety check asked Stripe a question the current Stripe API no longer answers (filtering the transfer list by source charge), so verification failed every time and the fail-safe refused every retry. The check now reads the transfers created since the charge and matches them itself. The fail-safe itself is unchanged: if the already-transferred amount can't be fully verified, nothing is ever sent.
* Fixed: an order whose products have no Split Pay recipient configured no longer logs a scary "every transfer attempt failed" note. When there is simply nothing to transfer, the order note now says so plainly and the order is marked processed, so it is never mistaken for a failure or picked up by the auto-retry.
* Fixed: Dokan Stripe Express orders whose transaction ID is already a Stripe charge can now use Retry Split Pay Transfers without treating that charge as a PaymentIntent. Source-charge limit errors now show charge-headroom guidance unless Stripe explicitly reports a currency mismatch, and only genuine live/test destination mismatches raise the persistent mode-mismatch notice.
* Fixed: the Dokan vendor Stripe Payouts page now uses Dokan's standard dashboard wrapper, preventing its content from overlapping the vendor navigation on desktop or mobile.
* Fixed: when a retry safety stop cannot verify Stripe transfer headroom, every retry attempt fails, or an extension throws unexpectedly, the order remains visibly failed and retryable instead of receiving a false completion note. A running automatic retry can still queue its single deduplicated successor.
* Fixed: a transfer or reversal delayed by another Split Pay money/settings operation is now recovered through a bounded, deduplicated background retry instead of being silently missed. Replays keep the original idempotency identity, and an incomplete reversal is never marked finished.
* Fixed: distinct equal-amount FluentCart refunds now use distinct stable reversal identities, so a second legitimate refund cannot be mistaken for a replay of the first.
* Improved (WCFM Marketplace): with "derive each vendor's share from their WCFM commission" enabled, a per-vendor commission override entered under WCFM's "Percent + Fixed" mode with the fixed field left blank is now honored. Previously only the plain "Percent" mode was read, so those vendors fell back to the global/manual percentage and the log warned it could not resolve their rate.
* Improved (WCFM Marketplace): with automatic product linking enabled, a vendor's product created or edited from the WordPress admin now links to the vendor's connected Stripe account even when Split Pay's product tab is never opened — matching what already happened for products saved from the vendor's own dashboard. Existing manual splits are never changed.
* Fixed (WCFM Marketplace): when the WCFM integration is enabled, Guard and Reconcile no longer filter WCFM settings or mark commission rows from a single transfer callback. They block only WCFM's scheduled and order-status automatic withdrawals. Orders paid by WCFM's Stripe Split or Wirecard checkout gateway stop Split Pay before any Stripe lookup and persist as a clean no-op, preventing a duplicate payout; manual withdrawals remain available and are disclosed in status.
* Improved: when the "Retry Split Pay Transfers" safety-stop can't verify the amount already transferred, the order note now links straight to your Stripe API keys and reminds you to check that the key isn't restricted (it must be allowed to read Charges and Transfers) — so a restricted key surfaces as an actionable fix instead of an endless "try again."
* Improved (WCFM Marketplace): the Integrations status now warns when a connected vendor account hasn't finished Stripe onboarding (its Transfers capability is off), with a link to your Stripe Connect accounts — so you see it before an order rather than only when a payout is skipped.

= 3.8.1 =
* Fixed: the Connected Stripe Account selector on Global Transfer Settings could show "[object Object]" instead of the business name on some sites (typically sites cloned from a template, or where another plugin loads its own copy of the dropdown library). The name and its Live/Test indicators now render correctly everywhere.
* Fixed: the Transfer Confirmation email's "Tax Transfer to" line displayed the product commission percentage instead of the tax transfer percentage — the transferred amount was always correct; only the label was wrong. It now shows the correct percentage (100% when Tax Transfer is set to "All").
* Fixed: vendor Stripe accounts connected in Test mode now register in Split Pay. Completing the test-mode connect link records the account immediately, and "Refresh from Stripe" now reads the same keys the connect link used, so a test-connected account no longer stays "Not connected."
* Added: a "Reset / reconnect accounts" control so you can clear and re-sync your connected accounts without uninstalling the plugin. "Refresh from Stripe" now also prunes accounts that no longer exist in Stripe, so deleted/phantom accounts disappear cleanly.
* Fixed: the Connect Status "some vendors aren't connected in both modes" warning no longer appears on stores that only use Live mode (or only Test) — it now only asks for the modes you actually have a platform key for.
* Fixed: the vendor onboarding page now shows a clear, actionable message instead of a raw Stripe error ("Connect platforms cannot create new accounts…") when the saved key is scoped to a connected account rather than a platform account.
* Fixed: the WCFM "double-pay risk" banner is now mode-aware — it confirms when Guard mode is neutralizing WCFM's payouts instead of always alarming, and reports WCFM's true payout configuration. Added a clear notice when the WCFM integration is off but its settings have been changed.
* Added: set the Connected Account, Transfer Amount and Shipping Transfer Value once at the product level for a variable product and have them applied to every variation automatically — any per-variation values you set still take precedence. Clearer section labeling in the variation editor, and an inline hint when a product's vendor isn't connected to Stripe yet.
* Added: Split Pay now honors a vendor's WCFM per-vendor commission override (not just membership-tier plans) when the WCFM commission source is enabled.
* Fixed: an order that WooCommerce auto-cancelled (for example, an unpaid order cancelled by the hold-stock timer) but whose card was charged later now has its vendor split completed, instead of the transfer being silently missed. Paid-but-cancelled orders are also flagged and can be retried manually.
* Fixed: per-product shipping transfers now apportion the order's shipping charge across its line items by quantity, so each product routes only its own quantity-weighted share and every item's share adds up to exactly the shipping you collected — a cent-level correction on orders with more than one line item. The product Shipping Transfer fields now explain how the share is calculated, and the shipping field's "Global Transfer Value" link label is corrected to "Global Shipping Transfer Value".
* Fixed: vendor self-onboarding via the [split_pay_vendor_connect] shortcode and the "Connect with Stripe" button now use the same platform key you save on the Integrations tab. This resolves cases where onboarding failed outright with "Could not start Stripe onboarding" (admin) or a "$config must be a string" error (vendor).
* Fixed: per-product shipping transfers are now calculated by Split Pay itself instead of depending on a WooCommerce Analytics helper — so stores with the Analytics feature turned off now get the correct per-item shipping share instead of $0.00.
* Fixed: refunding shipping now reverses the correct portion of each vendor's shipping transfer. Previously a shipping-only refund could reverse too little (and a goods-only refund too much) because shipping and product transfers were reversed by the same overall ratio.
* Fixed: line-item refunds now reverse the correct vendor transfer even for WPML/Polylang-translated products, parent-level splits on variable products, and WCML variations — cases where the ordered product differs from the one the split was configured on, which previously could reverse nothing.
* Fixed: retrying transfers on an order is now double-pay-safe. A retry seeds its ceiling from Stripe's own record of what was already sent for the charge (rather than the local log, which can under-count), and if a recomputed payout no longer matches what a vendor was already paid, the retry stops before sending anything and leaves an order note to reconcile.
* Added: when a vendor transfer is planned but can't be sent — for example a per-product shipping transfer below Stripe's $1 minimum, or an add-on with no connected account — Split Pay now records the reason in the order notes and shows an honest "N of M transfers sent" badge instead of a green all-clear.
* Added: a dedicated "split-pay" log under WooCommerce → Status → Logs (with a "View log" link on the Transfers tab), so transfer activity and any skipped legs are readable even when WooCommerce-Stripe's own logging is off.
* Changed: the Stripe webhook status is now verified against Stripe rather than a cached flag, so a store whose webhook endpoint was removed no longer shows a false "configured" checkmark. The Connect Status tab now shows each mode's webhook health and when its last event was received.
* Changed: corrected admin guidance that incorrectly implied Stripe fees cap transfers at about 97% of a sale. Split Pay routes transfers on the charge (source_transaction), so up to 100% can go to vendors; the notice now explains this. The genuine over-100% validation error is unchanged.
* Added: a pre-flight warning when product splits total 100% (or more) while "Adjust transfers for coupons" is off, so a coupon can't quietly push planned transfers past what the order actually charged. Notice only — payouts are unchanged.
* Added: optional order-fee routing. Map a WooCommerce order fee by name to a connected account (with a percentage, default 100%) on the Global Transfer Settings tab, and Split Pay routes that fee to the vendor alongside the product splits. Off by default and ignored entirely when unconfigured; negative/zero fees are never transferred; fees route ex-tax.
* Fixed: "Sync connected accounts" on the Integrations tab now pulls in both your Test and Live vendors in one click whenever you have a key saved for both modes. Previously it only ever looked at the mode your store was currently switched to, so a live store whose vendors had onboarded in test just reported "Synced 0" with no hint that they existed. The result now tells you how many were found in each mode, and if one mode can't be reached the other still syncs.
* Added: choose the type of Stripe connected account vendors get when they onboard — Standard (default) or Express — under Vendor Onboarding. Express gives vendors the Stripe-hosted Express Dashboard and suits platforms configured for Express; both use Stripe-hosted onboarding. Existing accounts are unaffected, and developers can select Custom or adjust other supported Accounts v1 creation parameters via the spp_account_create_args filter.
* Fixed: FluentCart refunds now reverse the vendor's Split Pay transfers. The refund webhook handler required a payload field FluentCart never sends, so refunds never clawed anything back — the merchant absorbed every refund while the vendor kept their split. Full refunds reverse each transfer in full; partial refunds reverse each vendor's share of that specific refund (never double-counting earlier partials). If a partial refund's amount can't be determined from Stripe, nothing is reversed and an order note tells you to reverse manually — the safe direction.
* Added: FluentCart chargebacks now reverse vendor transfers automatically. A dispute that withdraws funds reverses each vendor's share of the disputed amount at creation; a dispute inquiry (no funds withdrawn) only adds a note, and if it later closes as lost the reversal runs then. Winning a dispute leaves an explanatory note. One dispute can never reverse twice, and a re-delivered webhook is ignored.
* Changed: the webhook buttons are now read-only checks. "Check Webhook" (Stripe Configuration) verifies the WooCommerce Stripe endpoint exists; "Check webhooks" (Integrations tab) counts the active endpoints on each key. Split Pay no longer adds transfer.* events to any webhook endpoint: nothing consumed them (transfers are order-driven), the Integrations sync edited every endpoint on the Stripe account including other sites' endpoints, and on WooCommerce Stripe the modification caused the gateway to rebuild its endpoint (rotating the webhook secret) on its next plugin update. Events previously added are harmless and are cleaned up by WooCommerce Stripe itself over time.
* Fixed: the Connect Status "Last Stripe event received" reading always showed "No events recorded yet" — it read a WooCommerce Stripe option name that has never existed. It now reads the gateway's real webhook-monitoring timestamps.
* Fixed: the automatic transfer retry no longer pays vendors on an order that was fully refunded while the retry was waiting. A refunded order now goes through the same charge-payability check as cancelled/failed orders, which refuses to send anything when the charge shows a refund.

= 3.8.0 =
**Behavior changes when updating — please read before upgrading a live store:**
* Transfers now fire for ANY order that carries a Stripe charge from your platform account, whichever Stripe-backed gateway took the payment — previously only the official WooCommerce Stripe gateway and Payment Plugins for Stripe triggered transfers. Charges that are not in your platform account are detected and skipped with a clear order note, so a transfer is never misfired. If you use a third-party Stripe gateway and have been paying those vendors manually, stop after updating — Split Pay handles those orders now.
* FluentCart subscription renewals are now split automatically (details below) — recurring charges pay the vendor their configured percentage with no setting change.
* Per-product shipping transfers and Product Extras (PEWC) add-on transfers now actually fire when configured — both were silently broken in earlier releases. If you configured them in the past, those transfers begin with this update.
* The Transfer Confirmation email (enabled by default, but silently broken since 3.7.0) resumes sending; disable it in settings if you no longer want it.
* The WCFM and Dokan marketplace integrations are fully OPT-IN: nothing changes on a marketplace site until you turn on the integration's master switch on the Integrations tab.

* Added: a first-run setup wizard that walks a new install from zero to its first automatic transfer — enter your Stripe platform key, confirm your platform account, sync connected accounts and set a default split, then a readiness check — reachable on activation and from the Get Started links.
* Added: WCFM Marketplace integration (opt-in — enable it on the Integrations tab) — vendors who register through WCFM are automatically given the Split Pay vendor role, so Stripe Connect onboarding triggers with no admin action and their splits run.
* Added: a "Connect with Stripe" button right inside the WCFM vendor dashboard, and new vendor products are auto-linked to that vendor's connected Stripe account (with a one-click back-fill for products created before the vendor connected).
* Added: optionally drive each vendor's payout percentage from their WCFM membership tier (transfer % = 100 − the plan's commission %), resolved automatically at order time and updated whenever a vendor upgrades or downgrades — no per-product edits.
* Added: a Marketplaces section on the Integrations tab showing WCFM status, how many vendors are connected, products linked, and an always-on double-pay safety check with selectable coexistence modes (warn / reconcile / guard).
* Added: Vendor Automation (PRO, opt-in) — automatically create a product for each vendor the moment they finish Stripe onboarding, assigned to their connected account at a configurable vendor share percentage. Works hands-off with Name Your Price plugins so customers can pay any amount.
* Added: Vendor payment QR codes (PRO, opt-in) — each vendor gets a downloadable QR code linking to their product, shown on their dashboard and via the new `[split_pay_vendor_qr]` shortcode. Generated in the browser, no external services.
* Added: Transaction emails (PRO, opt-in) — notify the vendor when a transfer to their account succeeds and/or the customer when their money has been sent.
* Added: Customizable order-received message (PRO, opt-in) for orders containing split-pay products, with a `{vendor_name}` placeholder.
* Added: `spp_vendor_onboarding_completed` and `spp_vendor_disconnected` action hooks for developers.
* Improved: every payout Split Pay creates is now tagged in Stripe with metadata (split_pay=1), so the plugin's own transfers can be identified with certainty during reconciliation and reporting.
* Fixed: the front-end `[split_pay_vendor_connect]` flow now confirms onboarding completion when the vendor returns from Stripe — previously vendors kept seeing the "Resume Stripe Onboarding" state until an admin-side sync.
* Added: visibility for failed vendor bank payouts — if a vendor's automatic Stripe payout to their bank bounces (closed or invalid account, etc.), Split Pay now records it and lists it on the Platform Status tab so you can ask the vendor to fix their bank details. The transferred funds are not lost (they return to the vendor's Stripe balance) and Split Pay takes no money action; previously a bounced payout was completely invisible.
* Added: FluentCart subscription renewals are now split, not just the first order — every recurring renewal charge automatically pays the vendor their configured percentage, using the same per-product split settings already in place. Each renewal is paid exactly once, and PayPal renewals are left untouched.
* Added: automatic refund reclaim (PRO, opt-in) — when a refund reversal fails because the vendor's Stripe balance is too low, Split Pay records the unreversed amount as outstanding debt, then deducts it from that vendor's future transfers until cleared. Balances are shown per connected account, mode and currency on the Platform Status tab, with a one-click write-off; tracking is per-currency and per-mode, idempotent, and never over-charges a vendor. Off by default.
 * Fixed: a single un-renderable transfer record can no longer white-screen the admin. Each row in the Transfers (and other admin) tables now renders inside a safety net — if one row hits an unexpected error it is replaced with a small "could not be displayed" placeholder and logged, while the rest of the table loads normally, instead of taking down the whole page with a fatal.
* Fixed: on stores running both WooCommerce and FluentCart, a WooCommerce refund could reverse a FluentCart vendor's transfer when the two platforms' independent order-id sequences collided on the same number — refund reversals are now strictly scoped to the platform the refund belongs to.
* Fixed: coupon discounts are now applied to vendor transfers from WooCommerce's stored, post-discount line totals. Edge cases such as two or more stacked coupons, or a coupon later edited or whose type was translated (e.g. by WPML), can no longer cause a transfer to be computed on more than the discounted amount actually captured.
* Fixed: orders placed in a secondary language reliably pay the vendor configured on the original product, with an added WooCommerce Multilingual variation-link fallback for cases where WPML's own resolver isn't available at order time.
* Fixed: a genuinely live connected account is no longer mislabeled "TEST-mode account, unavailable in LIVE mode" after upgrading — account modes are now repaired automatically from your own transfer history, with no Stripe key required.
* Improved (safety): a built-in ceiling guarantees the sum of all vendor transfers for an order can never exceed the captured charge, preventing partial-payout failures from any misconfiguration.
* Improved: accidental duplicate vendor rows (the same vendor at the same rate on one product or variation) are collapsed when you save, preventing double payouts, with a dismissible heads-up.

= 3.7.5.1 =
* Fixed: orders no longer get stuck in "Pending payment" after a successful card payment when Split Pay is active — the Stripe payment notification is now correctly matched to the order even before WooCommerce records the charge.

= 3.7.5 =
* Fixed: vendors are never paid — or refunded — twice, even when a payment or refund notification arrives more than once.
* Added: automatic payout reversal if a delayed bank payment (ACH/SEPA) fails after vendors were already paid.
* Improved: clearer test-vs-live mode handling, reliable vendor-split saving, and a faster, more dependable Transfers tab.
* Improved: compatibility with other Stripe plugins, accessibility, security, and complete data cleanup on uninstall (incl. multisite).

= 3.7.4 =
* Fixed: Product vendor selection on new products persists (legacy save no longer clears meta when the account field is absent from POST; default editable vendor row on empty products).
* Fixed: Transfers tab lists transfers when Payment Plugins for Stripe is the active gateway (unified test/live mode detection + one-time transfer-log reconciliation).
* Fixed: Product Split Pay settings (vendor, percentage / amount, shipping) no longer get silently erased on saves that don't include the Split Pay tab fields (variable parent save, REST/API saves, third-party product saves, etc.).
* Fixed: Same erasure protection for product variations; vendor-only variation saves no longer wipe the selected vendor.
* Added: One-time upgrade migration rebuilds erased product settings from the transfer log (skips products that already have a vendor).
* Added: Perpetual per-product "Recover Split Pay settings from transfer log" tool on the WooCommerce product Split Pay tab (optional force-overwrite).
* Fixed: Per-product Recover panel is visible on the Split Pay tab (wrapper no longer uses WooCommerce's reserved `panel` class; now `spp-recovery-wrap`).
* Fixed: Admin paths no longer fatal with `WC_Stripe_Logger::log()` when only Payment Plugins' Stripe gateway is installed.
* Fixed: Transfers tab no longer fatals when a logged payment method doesn't map to an active gateway object.
* Fixed: Saved vendor stays visible on the product tab even when the account isn't in the synced-accounts list (orphan option shown).
* Fixed: Migrations no longer warn/fatal under wp-cron or CLI on some hosts.

= 3.7.3 =
* Fixed: `WC_Stripe_Logger::log()` fatals on Payment Plugins-only sites (namespaced 3.7.0 code paths now guarded).
* Fixed: Percentage splits on Name Your Price / customer-chosen-price orders use the paid line subtotal, not the catalog base price.
* Fixed: Vendor selection on the product Split Pay tab persists when percentage and amount are left empty.
* Fixed: Transfers tab empty while Stripe transfers succeeded (`stripe_mode` and related columns now written; `migration-373` backfills 3.7.0+ rows).

= 3.7.2 =
* Fixed: Removed blocking "above 97%" confirm popup on product save (could cancel saves).
* New: 97% / 100% aggregate transfer warnings show as dismissible admin notices instead.

= 3.7.1 =
* Compat: Tested up to WordPress 7.0.
* Fixed: `WC_Stripe_Logger::log()` fatals on Payment Plugins-only sites (legacy class paths guarded).

= 3.7.0 =
* New: FluentCart support.
* New: Integrations tab (per-gateway keys, webhook sync, account sync).
* New: Top-level Split Pay admin menu.
* New: Payment Plugins for Stripe WooCommerce gateway support.
* New: `[split_pay_vendor_connect]` vendor onboarding shortcode.
* New: Delayed Transfers (PRO) — hold transfers until order is Completed.
* New: Transfer log source column (WooCommerce / FluentCart).
* New: `spp_integrations`, `spp_register_integrations`, `spp_product_data_tab_classes` hooks.
* Improved: Activates with FluentCart only (WooCommerce not required).
* Improved: Shared connected accounts across integrations; unified TransferEngine for WC shipping/tax/product transfers.
* Fixed: Multi-account global percentage math restored to pre-3.7.0 behaviour.
* Fixed: Activation no longer requires the official WooCommerce Stripe gateway.
* Fixed: Transfer order notes use the order currency symbol.

= 3.6.4 =
* Fix webhook sync failing when stored endpoint IDs are stale, deleted, or mode-mismatched.
* Added URL-based fallback to find the correct webhook endpoint automatically.
* Fixed scoping bug with API key in live mode webhook sync path.

= 3.6.3 =
* Fix to multiple product transfers.
* Fix PEWC (Product Extra Options) transfer to use instance-based Stripe client.
* Freemius update.

= 3.6.2 =
* Metadata error fix.

= 3.6.1 =
* Fix undefined variable when order shipping method is not found in any zone.
* Fixed 500 error with Retry Split Pay Transfer.

= 3.6.0 =
* Payment methods — All WooCommerce Stripe methods supported; deferred methods wait for settlement.
* Refund handling (PRO) — Automatic proportional transfer reversals on WooCommerce refunds.
* Retry transfers (PRO) — New order action to retry failed transfers.
* Currency checks — Warnings when connected accounts are in a different country than the platform.
* Vendor roles (PRO) — Use any WordPress role instead of a single custom role.
* Setup checks — API key format validation, incomplete-config notices, and 97%+ transfer percentage warning.

= 3.5.9 =
* Fix to Transfers tab. 

= 3.5.8 =
* Update Freemius integration. 

= 3.5.7 =
* Fix for multisite network activation.

= 3.5.6 =
* Bulk editor improvements.

= 3.5.5 =
* Bulk Editor improvements
* Bugfix for database table creation on multisite. 

= 3.5.4 =
* Fixes to items not saving on settings.
* Improvements to Bulk Editor. 

= 3.5.3 = 
* Added Advanced Product Fields integration.
* Improved Bulk Editor mechanism.
* Updated Freemius SDK. 

= 3.5.2 = 
* WooCommerce Bundles plugin now supported. 
* Developer-friendly Actions/Filters added. 
* Tax transfer bugfix and email issue. 
* Warning add for non-supported 3rd party product types. 

= 3.5.1 = 
* Shipping tax handling improvements. 
* Update Freemius SDK. 

= 3.5.0 = 
* Tax handling improvements. 

= 3.4.9 = 
* Tax handling improvements. 

= 3.4.8 = 
* Major bug fixes and improvements.
* Reconfiguration of API key approach due to changes in WooCommerce Stripe Payment Gateway plugin.

= 3.4.7 = 
* Improved tax handling. 

= 3.4.6 = 
* Add Tax Handling. 

= 3.4.5 = 
* Updated translations. 

= 3.4.4 = 
* Updated translation .POT file. 
* Updates to UI. 
* Updated Freemius SDK. 

= 3.4.3 = 
* Added Transfer Confirmation email in WooCommerce settings.
* Fixes to bulk editor. 
* Fixes to Stripe Connect. 
* Coupon fixes due to changes in WooCommerce.  

= 3.4.2 =
* Correct usage of API keys in TEST/LIVE modes for Stripe Connect.

= 3.4.1 =
* Fix to Stripe Connect in TEST mode. 
* Fix for styling issue on Stripe Connect button. 

= 3.4 =
* Bulk Editor added! You can now bulk edit transfer details for all products and variations in the PRO version. 
* Update to Freemius SDK. 
* General bug fixes.

= 3.3.11 =
* Fix to 100% transfer calculation.
* Layout fix to product view.
* Update to Freemius SDK. 

= 3.3.10 =
* Stability improvements and bug fixes. 
* Updated strings translation. 
* Fix for shipping transfer value not working when standard transfer value was 0. 

= 3.3.9 =
* Added option to transfer order details to Stripe metadata. 
* Bug fixes to error mechanism.
* Improves to the Transfers Tab layout. 

= 3.3.8 =
* Fix to HPOS.
* Confirmed that the plugin works with Woo Subscriptions.  

= 3.3.7 =
* Added support for simple product types created by 3rd party plugins or themes. 
* Added support for Woo High-Performance Order Storage. 
* Updated Freemius SDK. 

= 3.3.6 =
* Updates to Stripe Connect mechanism.
* Fix to auto-deactivation of the free version on PRO upgrade. 

= 3.3.5 =
* Added Stripe Connect onboarding for Vendors. 
* Added fields for transferring a percentage or fixed amount of shipping fees.
* Added CSV export mechanism for transfers. 
* Updated Freemius SDK. 

= 3.3.4 =
* Bug fixes

= 3.3.3 = 
* Updated some text strings, upgrade mechanisms, and icons. 

= 3.3.2 = 
* Additional bug fixes for saving/deleting connected account settings.
* Extended capability of multiple connected accounts to product-level.

= 3.3.1 = 
* Updated Freemius SDK.
* Resolved bugs of not being able to save or remove selected connected account. 

= 3.3 =
* Multiple connected accounts now supported! 

= 3.2.10 =
* Coupon compatibility fix. 
* Update Freemius SDK. 

= 3.2.9 =
* Support for splitting payments coupons involved. 
* Fix for Stripe accounts synchronization issue. 
* Freemius SDK update. 

= 3.2.8 =
* Bugfix for displaying error message when unable to connect to platform accounts. 
* General bugfixes and stability improvements. 
* Freemius SDK update. 

= 3.2.7 =
* Database storage bugfix for free version. 
* Update to retrieving Object ID from Stripe. 

= 3.2.6 =
* Database storage bugfix. 

= 3.2.5 =
* Added Fixed Amount split payments.
* Added percentage-based and fixed amount split transfers to variable products in WooCommerce. 
* Added option to transfer shipping fees to connected accounts. 

= 3.2.4 =
* Fixed pagination issue with transfers tab.
* Fixed multiple-quantity order miscalculations. 

= 3.2.3 = 
* Implemented Stripe Connect mechanism.
* Using checkout total by default for splitting percentage instead of Subtotal.
* General bug fixes and stability improvements. 

= 3.2.2 = 
* Sanizations and escapes for WordPress.org compliance. 
* Fixed bug preventing the saving of WooCommerce products. 

= 3.2.1 = 
* Updated Freemius SDK to v2.4.5.
* General bug fixes and security improvements. 

= 3.2.0 =
* Added a premium feature allowing administrators to configure different split percentages at the product level.
* Removed Exclude Shipping and Exclude Tax settings (plugin now automatically excludes both).

= 3.1.0 =
* Fixed a bug with the Exclude Shipping and Exclude Tax settings.
* Tested with WooCommerce 5.2.2.
* Tested with WordPress 5.7.1.

= 3.0.1 =
* Tested with WooCommerce 5.2.1.
* Minor tweaks to installation instructions and screenshot.

= 3.0.0 =
* Complete code refactor to streamline plugin.
* Tested with WooCommerce v5.2.
* Moved plugin settings menu.
* Added plugin link to documentation.
* Updated to use WooCommerce currency setting.

= 2.5.4 =
* Tested with WordPress 5.7
* Tested with WooCommerce 5.1

= 2.5.3 = 
* Tested with WordPress 5.5
* Tested with WooCommerce 4.3.2

= 2.5.2 =
* Updating licensing platform to Freemius

= 2.5.1 =
* Fix for plugin update banner

= 2.5.0 =
* Rewrote Stripe routine to handle multiple sites
* Some code refactoring for efficiency

= 2.4.3 =
* Added check to verify Stripe source ID matches existing WC ID
* Fixed update banner image

= 2.4.2 =
* Updated Transfer section total record count to include test/live mode filter

= 2.4.1 =
* Fixed WordPress support tag

= 2.4.0 =
* Implemented new Transfers section, including Stripe reference IDs
* Filter the Transfers section based on Stripe test mode vs live mode
* Removed old dashboard

= 2.3.1 =
* Pre-release for 2.4
* Added plugin upgrade functionality to accommodate future database changes
* Created new transfer log database table
* Added instance of core WP table class
* Updated uninstall logic

= 2.3.0 =
* Added exception handling for Stripe Connected Account not found ("No such destination")
* Enhanced so we will only process a webhook if the statement descriptor configured in WooCommerce > Settings > Payments matches the statement descriptor returned in the webhook response

= 2.2.1 =
* Fixed bug in webhook check

= 2.2 =
* Added plugin update checks for licensed instances

= 2.1 =
* Added licensing

= 2.0 =
* Moved from a stand-alone WordPress dashboard item to a tab inside WooCommerce Settings
* Merged features into standard WordPress plugin structure
* Sets WooCommerce Stripe Gateway as a plugin dependency
* Removed separate settings for Stripe keys and test/live mode; now gets those settings from the WooCommerce Stripe Gateway plugin
* Eliminated custom styles
* Added an option to exclude sales tax from transfer calculations

= 2.0 =
* Initial version of the plugin.
