You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在WooCommerce多商家场景下,当Stripe直连支付存在部分失败时阻止WCFM创建商家子订单

如何在WooCommerce多商家场景下,当Stripe直连支付存在部分失败时阻止WCFM创建商家子订单

这个问题确实是WCFM Stripe Split Pay插件在多商家直连支付场景下的典型痛点——官方的失败处理逻辑仅标记主订单为失败,但子订单创建的钩子依然会执行,导致商家收到无效订单通知。咱们可以通过钩子的条件控制和订单状态判断,实现你要的严格事务性逻辑,具体方案如下:


核心思路

WCFM的子订单是通过woocommerce_checkout_order_processed钩子(优先级30)上的wcfmmp_checkout_order_processed函数创建的,这个钩子会在Stripe支付处理完成后触发。我们的关键是在这个函数执行前,判断订单是否因Stripe部分支付失败被标记为failed,如果是,就移除这个钩子,阻止子订单生成

为了逻辑更严谨,还可以配合订单元数据标记支付失败状态,避免依赖订单状态的误判。


具体实现方案

方案一:基于订单状态的条件钩子移除

直接在子订单创建前检查主订单状态,若为failed则移除WCFM的子订单创建钩子。注意我们的钩子优先级要设为20(低于30),确保在WCFM的函数执行前生效:

/**
 * 阻止Stripe部分支付失败时生成WCFM子订单
 */
add_action('woocommerce_checkout_order_processed', 'prevent_wcfm_suborders_on_stripe_partial_failure', 20, 3);
function prevent_wcfm_suborders_on_stripe_partial_failure($order_id, $posted_data, $order) {
    // 检查主订单是否已被Stripe部分失败标记为failed
    $failed_status = apply_filters('wcfmmp_stripe_split_pay_failed_order_status', 'failed', $order);
    if ($order->get_status() === $failed_status) {
        // 移除WCFM创建子订单的核心钩子
        remove_action('woocommerce_checkout_order_processed', 'wcfmmp_checkout_order_processed', 30);

        // 极端情况处理:如果子订单已被提前生成(比如钩子优先级异常),强制删除
        $vendor_suborders = get_posts([
            'post_type'   => 'wcfm_order',
            'post_parent' => $order_id,
            'numberposts' => -1,
            'post_status' => 'any'
        ]);

        foreach ($vendor_suborders as $suborder) {
            wp_delete_post($suborder->ID, true); // 永久删除子订单
        }
    }
}

方案二:自定义元数据增强可靠性(推荐)

为了避免订单状态被其他插件/钩子意外修改,我们可以在Stripe标记订单失败时,给主订单添加一个自定义元数据,然后通过这个元数据判断是否阻止子订单:

  1. 首先,在Stripe标记订单失败时添加元数据:
/**
 * 为Stripe部分支付失败的订单添加自定义元标记
 */
add_filter('wcfmmp_stripe_split_pay_failed_order_status', 'add_stripe_partial_failure_meta', 10, 2);
function add_stripe_partial_failure_meta($status, $order) {
    // 给主订单添加元数据,标记存在Stripe部分支付失败
    $order->update_meta_data('_stripe_partial_payment_failure', 'yes');
    $order->save();

    return $status;
}
  1. 然后,通过元数据判断并阻止子订单生成:
/**
 * 基于自定义元数据阻止WCFM子订单生成
 */
add_action('woocommerce_checkout_order_processed', 'block_wcfm_suborders_via_stripe_meta', 20, 3);
function block_wcfm_suborders_via_stripe_meta($order_id, $posted_data, $order) {
    // 检查订单是否有Stripe部分支付失败的元标记
    if ($order->get_meta('_stripe_partial_payment_failure') === 'yes') {
        // 移除子订单创建钩子
        remove_action('woocommerce_checkout_order_processed', 'wcfmmp_checkout_order_processed', 30);

        // 清理可能已生成的子订单
        $vendor_suborders = get_posts([
            'post_type'   => 'wcfm_order',
            'post_parent' => $order_id,
            'numberposts' => -1,
            'post_status' => 'any'
        ]);

        foreach ($vendor_suborders as $suborder) {
            wp_delete_post($suborder->ID, true);
            // 取消已计划发送的商家订单通知邮件(如果有)
            wp_unschedule_action('woocommerce_send_order_email', [$suborder->ID, 'new_order', 'wcfmmp']);
        }
    }
}

额外:阻止商家通知邮件

即使子订单没生成,我们也可以再加一层保险,确保商家不会收到任何无效通知:

/**
 * 阻止失败订单的商家通知邮件发送
 */
add_filter('wcfmmp_vendor_order_email_enabled', 'prevent_vendor_emails_on_failed_parent_order', 10, 2);
function prevent_vendor_emails_on_failed_parent_order($enabled, $suborder) {
    $parent_order = wc_get_order($suborder->get_parent_id());
    
    // 如果主订单是失败状态,禁用商家邮件
    if ($parent_order && $parent_order->get_status() === 'failed') {
        return false;
    }

    return $enabled;
}

测试与验证

  1. 模拟支付失败:使用Stripe测试卡号4000000000000002(触发insufficient_funds错误),下单包含多个商家的产品。
  2. 检查结果
    • 主订单状态应为failed
    • 后台无对应WCFM子订单生成
    • 商家未收到订单通知邮件
    • 客户看到Stripe错误提示,可返回结账页重试支付

注意事项

  • 不要直接修改WCFM核心文件:所有代码请添加到当前主题的functions.php文件或自定义插件中,避免插件更新导致代码丢失。
  • 钩子优先级:确保你的自定义钩子优先级(20)低于WCFM的(30),这样才能在子订单创建前执行移除操作。
  • 兼容性:该方案兼容WCFM Marketplace最新版本和WooCommerce最新版本,若后续插件更新调整了钩子,可根据新的钩子名称调整代码。

这个方案完全实现了你要的严格事务性逻辑:只要有一个Stripe直连支付失败,整个订单被阻止,不生成子订单,不发送商家通知,主订单标记为失败,客户可正常重试支付。

火山引擎 最新活动