Overview#

Split Pay exposes a set of WordPress filters that allow developers to programmatically modify transfer settings at runtime. These filters are useful for dynamic transfer logic, custom product types, multivendor scenarios, and any case where the admin UI settings are not sufficient.

All filters follow standard WordPress conventions. Add them in your theme's functions.php, a custom plugin, or a code snippets plugin.

Developer filters are available in both the free and Pro versions of Split Pay.


Integration architecture hooks 3.7.0+#

The 3.7.0 modular adapter architecture introduced a small set of hooks for registering additional platform/gateway integrations and for inspecting transfer-time events from any integration. These are the hooks you reach for if you’re building your own platform adapter or wiring Split Pay into a custom workflow.

spp_register_integrations (action) 3.7.0+#

Fires once at plugins_loaded with the shared IntegrationRegistry. Use it from third-party code to register additional integrations alongside the bundled WooCommerce and FluentCart adapters.

add_action( 'spp_register_integrations', function( $registry ) {
    if ( class_exists( 'My_Plugin\\Integration\\MyPlatformAdapter' ) ) {
        $registry->register( new \My_Plugin\Integration\MyPlatformAdapter() );
    }
} );

spp_integrations (filter) 3.7.0+#

Filter the populated IntegrationRegistry after the action above runs. Lets you inspect or substitute the full set of integrations Split Pay will use.

add_filter( 'spp_integrations', function( $registry ) {
    return $registry;
} );

spp_product_data_tab_classes (filter) 3.7.0+#

Filter the WooCommerce product-tab visibility classes for the Split Pay product data tab. By default the tab only appears for show_if_simple products. Add additional classes to opt other product types in.

add_filter( 'spp_product_data_tab_classes', function( $classes ) {
    $classes[] = 'show_if_subscription'; // Add for WC Subscriptions products
    $classes[] = 'show_if_variable-subscription';
    return $classes;
} );

spp_before_process_transfers (action) 3.7.0+#

Fires immediately before the TransferEngine processes the transfer set for an order. Receives the platform-specific order adapter, the integration slug (e.g. 'fluentcart'), and the Stripe charge ID. Useful for logging, auditing, or last-minute conditional skip logic.

add_action( 'spp_before_process_transfers', function( $orderAdapter, $integration, $chargeId ) {
    error_log( "[SPP] About to process transfers for {$integration} order {$orderAdapter->getOrderId()} (charge {$chargeId})" );
}, 10, 3 );

spp_after_process_transfers (action) 3.7.0+#

Fires after the engine finishes processing transfers for an order, regardless of success/failure. Same parameters as the “before” action. Use this for post-transfer auditing, custom notifications, or analytics events.

add_action( 'spp_after_process_transfers', function( $orderAdapter, $integration, $chargeId ) {
    do_action( 'my_analytics/track', 'split_pay_transfer_completed', [
        'integration' => $integration,
        'order_id'    => $orderAdapter->getOrderId(),
        'charge_id'   => $chargeId,
    ] );
}, 10, 3 );

spp_fc_order_transferable_items (filter) 3.7.0+#

FluentCart-only. Filter the array of transferable line items returned by FCOrderAdapter::getTransferableItems(). Use it to suppress particular line items from triggering transfers (for example, a service fee that should not be split).

add_filter( 'spp_fc_order_transferable_items', function( $items, $order ) {
    return array_filter( $items, function( $item ) {
        return ! str_starts_with( $item['name'] ?? '', 'Service Fee' );
    } );
}, 10, 2 );

spp_transfer_metadata (filter) 3.7.0+#

Platform-agnostic transfer metadata filter. Currently fired by the FluentCart integration and intended as the unified hook for all integrations going forward. Receives the metadata array, the order object (or null), and the integration slug.

add_filter( 'spp_transfer_metadata', function( $metadata, $order, $integration ) {
    $metadata['source_integration'] = $integration;
    return $metadata;
}, 10, 3 );

Global filters#

These filters modify the global transfer settings that apply to all products without product-level overrides.

spp_get_stored_accounts#

Filter the list of connected Stripe accounts available for selection. Receives an array of account objects.

add_filter( 'spp_get_stored_accounts', function( $accounts ) {
    // Add a dynamically-registered connected account
    $accounts[] = array(
        'account_id' => 'acct_1234567890',
        'label'      => 'Vendor — Dynamic Account',
    );
    return $accounts;
} );

spp_global_connect_id_settings#

Filter the global transfer settings array. This is the main filter for overriding global behavior. The settings array includes keys for connect_id, transfer_type, transfer_percentage, transfer_amount, and shipping-related fields.

add_filter( 'spp_global_connect_id_settings', function( $settings ) {
    // Override the global connected account
    $settings['connect_id'] = 'acct_VENDOR_ABC';

    // Switch to percentage-based and set to 15%
    $settings['transfer_type'] = 'percentage';
    $settings['transfer_percentage'] = 15;

    return $settings;
} );

Product-level filters#

These filters modify transfer settings for individual products. Each filter receives the current value and the product ID ($post_id), allowing you to apply conditional logic per product.

Platform-agnostic since 3.7.0. Each spp_before_save_product_* filter listed below now also fires from the FluentCart product save path (FCProductAdapter::saveProductSplitPaySettings()) in addition to the WooCommerce save path. The same callback runs for both platforms, so you can write platform-agnostic logic.

spp_before_save_product_accounts#

Filter the connected account ID(s) assigned to a product.

add_filter( 'spp_before_save_product_accounts', function( $accounts, $post_id ) {
    // Route all products in category "electronics" to a specific vendor
    if ( has_term( 'electronics', 'product_cat', $post_id ) ) {
        $accounts = array( 'acct_ELECTRONICS_VENDOR' );
    }
    return $accounts;
}, 10, 2 );

spp_before_save_product_types#

Filter the transfer type for a product. Accepted values: 'percentage' or 'fixed'.

add_filter( 'spp_before_save_product_types', function( $type, $post_id ) {
    // Force all digital products to use fixed transfers
    $product = wc_get_product( $post_id );
    if ( $product && $product->is_virtual() ) {
        $type = 'fixed';
    }
    return $type;
}, 10, 2 );

spp_before_save_product_transfer_percentage#

Filter the transfer percentage for a product.

add_filter( 'spp_before_save_product_transfer_percentage', function( $percentage, $post_id ) {
    // Give premium vendors a higher split
    $vendor_tier = get_post_meta( $post_id, '_vendor_tier', true );
    if ( $vendor_tier === 'premium' ) {
        $percentage = 25;
    }
    return $percentage;
}, 10, 2 );

spp_before_save_product_transfer_amount#

Filter the fixed transfer amount for a product.

add_filter( 'spp_before_save_product_transfer_amount', function( $amount, $post_id ) {
    // Set a minimum transfer amount of $5
    if ( $amount < 5 ) {
        $amount = 5;
    }
    return $amount;
}, 10, 2 );

spp_before_save_product_shipping_transfer_type#

Filter the shipping transfer type for a product. Accepted values: 'percentage' or 'fixed'.

add_filter( 'spp_before_save_product_shipping_transfer_type', function( $type, $post_id ) {
    return 'percentage';
}, 10, 2 );

spp_before_save_product_shipping_transfer_percentage#

Filter the shipping transfer percentage for a product.

add_filter( 'spp_before_save_product_shipping_transfer_percentage', function( $percentage, $post_id ) {
    return 50; // Transfer 50% of shipping to vendor
}, 10, 2 );

spp_before_save_product_shipping_transfer_amount#

Filter the fixed shipping transfer amount for a product.

add_filter( 'spp_before_save_product_shipping_transfer_amount', function( $amount, $post_id ) {
    return 3.00; // Always transfer $3.00 for shipping
}, 10, 2 );

Variable product filters#

These filters follow the same pattern as product-level filters but apply to individual product variations. They use the variable_product prefix in the filter name and receive the variation's post ID.

Available variable product filters#

Filter Name Description
spp_before_save_variable_product_accounts Connected account(s) for a variation
spp_before_save_variable_product_types Transfer type for a variation
spp_before_save_variable_product_transfer_percentage Transfer percentage for a variation
spp_before_save_variable_product_transfer_amount Fixed transfer amount for a variation
spp_before_save_variable_product_shipping_transfer_type Shipping transfer type for a variation
spp_before_save_variable_product_shipping_transfer_percentage Shipping transfer percentage for a variation
spp_before_save_variable_product_shipping_transfer_amount Fixed shipping transfer amount for a variation

Usage follows the same pattern as product-level filters:

add_filter( 'spp_before_save_variable_product_transfer_percentage', function( $percentage, $variation_id ) {
    // Variation-specific logic
    $variation = wc_get_product( $variation_id );
    $size = $variation->get_attribute( 'size' );

    if ( $size === 'XL' || $size === 'XXL' ) {
        $percentage = 20; // Higher split for larger sizes
    }

    return $percentage;
}, 10, 2 );

Transfer-time metadata filters#

These filters run at the moment a Stripe Transfer is created, allowing you to modify the metadata array attached to each transfer. This is useful for adding custom tracking data, order details, or vendor-specific information to Stripe's transfer metadata.

Transfer metadata filters fire during webhook processing (when payment_intent.succeeded is received). They do not fire during admin save actions.

spp_global_account_wise_meta_data#

Filter the metadata attached to global transfers (both percentage and fixed). Receives the metadata array, the originating store order ID (a WooCommerce order ID on Stack A or a FluentCart order ID on Stack B — not WooCommerce-specific), and the connected account ID.

add_filter( 'spp_global_account_wise_meta_data', function( $meta_data, $order_id, $account_id ) {
    // Add custom tracking data to global transfers.
    // $order_id is a store order ID (WC or FC) - look it up via the
    // appropriate API for your platform if you need the order object.
    $meta_data['vendor_region'] = get_user_meta( get_current_user_id(), 'region', true );
    $meta_data['internal_ref']  = 'GLOBAL-' . $order_id;

    return $meta_data;
}, 10, 3 );

spp_product_wise_meta_data#

Filter the metadata attached to product-level transfers. Receives the metadata array, the originating store order ID (WooCommerce or FluentCart), and the connected account ID.

add_filter( 'spp_product_wise_meta_data', function( $meta_data, $order_id, $account_id ) {
    // Include the product name in the transfer metadata.
    // wc_get_product() is WC-specific; on FluentCart use the
    // platform's product accessor.
    if ( isset( $meta_data['Product Id'] ) && function_exists( 'wc_get_product' ) ) {
        $product = wc_get_product( $meta_data['Product Id'] );
        if ( $product ) {
            $meta_data['Product Name'] = $product->get_name();
        }
    }

    return $meta_data;
}, 10, 3 );

Shipping transfer metadata filters#

These filters work identically to the payment transfer filters but apply to shipping fee transfers:

Filter Name Description
spp_shipping_transfer_meta_data Metadata for global shipping transfers (account-level)
spp_global_shipping_transfer_meta_data Metadata for global shipping transfers (percentage/fixed)
spp_product_wise_shipping_transfer_meta_data Metadata for product-level shipping transfers

All shipping metadata filters receive the same three parameters: $meta_data, $order_id, and $account_id.

add_filter( 'spp_shipping_transfer_meta_data', function( $meta_data, $order_id, $account_id ) {
    $meta_data['shipping_carrier'] = 'USPS';
    return $meta_data;
}, 10, 3 );

Complete filter reference#

Filter Name When it Fires Parameters
spp_register_integrations (action)plugins_loaded — integration registry boot (3.7.0+)$registry
spp_integrationsplugins_loaded — after registry is populated (3.7.0+)$registry
spp_product_data_tab_classesWooCommerce product edit screen — tab visibility (3.7.0+)$classes
spp_before_process_transfers (action)Transfer time — before TransferEngine runs (3.7.0+)$orderAdapter, $integration, $chargeId
spp_after_process_transfers (action)Transfer time — after TransferEngine runs (3.7.0+)$orderAdapter, $integration, $chargeId
spp_fc_order_transferable_itemsFluentCart — reading transferable line items (3.7.0+)$items, $order
spp_get_stored_accountsAdmin UI — account dropdowns$accounts, $level
spp_global_connect_id_settingsAdmin — saving global settings$settings
spp_before_save_product_accountsAdmin — saving product$accounts, $post_id
spp_before_save_product_typesAdmin — saving product$type, $post_id
spp_before_save_product_transfer_percentageAdmin — saving product$percentage, $post_id
spp_before_save_product_transfer_amountAdmin — saving product$amount, $post_id
spp_before_save_product_shipping_transfer_typeAdmin — saving product$type, $post_id
spp_before_save_product_shipping_transfer_percentageAdmin — saving product$percentage, $post_id
spp_before_save_product_shipping_transfer_amountAdmin — saving product$amount, $post_id
spp_before_save_variable_product_accountsAdmin — saving variation$accounts, $variation_id
spp_before_save_variable_product_typesAdmin — saving variation$type, $variation_id
spp_before_save_variable_product_transfer_percentageAdmin — saving variation$percentage, $variation_id
spp_before_save_variable_product_transfer_amountAdmin — saving variation$amount, $variation_id
spp_before_save_variable_product_shipping_transfer_typeAdmin — saving variation$type, $variation_id
spp_before_save_variable_product_shipping_transfer_percentageAdmin — saving variation$percentage, $variation_id
spp_before_save_variable_product_shipping_transfer_amountAdmin — saving variation$amount, $variation_id
spp_global_account_wise_meta_dataTransfer time — global transfers$meta_data, $order_id, $account_id
spp_product_wise_meta_dataTransfer time — product transfers$meta_data, $order_id, $account_id
spp_shipping_transfer_meta_dataTransfer time — shipping transfers$meta_data, $order_id, $account_id
spp_global_shipping_transfer_meta_dataTransfer time — global shipping$meta_data, $order_id, $account_id
spp_product_wise_shipping_transfer_meta_dataTransfer time — product shipping$meta_data, $order_id, $account_id
spp_transfer_metadataTransfer time — all transfers (FluentCart today, all integrations going forward)$metadata, $order, $integration

Best practices#

  • Always return a value — Every filter callback must return the filtered value, even if unchanged.
  • Test in test mode — Use Stripe test mode to verify your filters produce the correct transfer amounts before going live.
  • Use a custom plugin — Placing filter code in a separate plugin (rather than functions.php) ensures it persists across theme changes.
  • Log for debugging — Use error_log() within your filter callbacks to trace values during development.
  • Check priority — If multiple filters modify the same value, use the priority parameter (default: 10) to control execution order.

Filters that set transfer amounts too high can result in transfer errors from Stripe. Ensure the total of all transfers for an order does not exceed the payment amount minus Stripe fees.