You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WooCommerce自定义支付网关外部跳转传参与回调实现方案

WooCommerce自定义支付网关跳转+回调实现方案

你现有代码已经完成了支付网关的基础挂载和后台配置,只需要补充订单提交跳转逻辑和回调验签更新订单逻辑即可,核心用到的WooCommerce内置能力不需要额外注册自定义路由,全部基于支付网关抽象类的规范和官方钩子实现。


核心实现逻辑说明

1. 订单提交跳转部分

不需要额外找提交订单的钩子,直接在自定义网关类中实现process_payment($order_id)方法即可,用户选择该支付方式点击提交订单时,WooCommerce会自动调用这个方法:

  • 方法内首先获取订单对象,将订单初始化为待支付状态
  • 组装需要传递给外部支付站点的参数:订单ID、商品ID集合、购物车hash(即需求中提到的购物车ID,存在订单_cart_hash meta中)、订单总金额、回调地址、验签串
  • 清空用户当前购物车,返回跳转指令,WooCommerce会自动带着参数跳转到你的外部支付站点

2. 支付回调部分

使用WooCommerce内置的API钩子注册回调地址,不需要自己写WordPress路由规则:

  • 钩子格式为woocommerce_api_{自定义回调标识},注册后回调地址固定为你的域名/wc-api/{自定义回调标识}/
  • 回调方法内首先做三层校验:验签是否合法、订单是否存在、回传支付金额和订单实际金额是否一致
  • 校验通过后更新订单状态为支付成功(WooCommerce标准状态为wc-processing,虚拟可下载商品可以设为wc-completed),记录支付流水和备注,返回成功响应;校验失败则记录错误,返回失败响应

完整修改后代码

add_filter( 'woocommerce_payment_gateways', 'add_your_gateway_class' );
function add_your_gateway_class( $methods ) {
    $methods[] = 'WC_Custom_PG'; 
    return $methods;
}

add_action( 'plugins_loaded', 'init_wc_custom_payment_gateway' );
function init_wc_custom_payment_gateway(){
    class WC_Custom_PG extends WC_Payment_Gateway {
        function __construct(){
            $this->id = 'wc_custom_pg';
            $this->method_title = 'Custom Payment Gateway';
            $this->title = 'Custom Payment Gateway';
            $this->has_fields = true;
            $this->method_description = 'Your description of the payment gateway';

            $this->init_form_fields();
            $this->init_settings();
            $this->enabled = $this->get_option('enabled');
            $this->title = $this->get_option( 'title' );
            $this->description = $this->get_option('description');
            // 新增配置项读取
            $this->external_pay_url = $this->get_option('external_pay_url');
            $this->callback_key = $this->get_option('callback_key');

            // 保存后台设置
            add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
            // 注册支付回调钩子
            add_action( 'woocommerce_api_wc_custom_pg_callback', array( $this, 'handle_payment_callback' ) );
        }

        public function init_form_fields(){
            $this->form_fields = array(
                'enabled' => array(
                    'title'         => 'Enable/Disable',
                    'type'          => 'checkbox',
                    'label'         => 'Enable Custom Payment Gateway',
                    'default'       => 'yes'
                ),
                'title' => array(
                    'title'         => 'Method Title',
                    'type'          => 'text',
                    'description'   => 'This controls the payment method title',
                    'default'       => 'Custom Payment Gateway',
                    'desc_tip'      => true,
                ),
                'description' => array(
                    'title'         => 'Customer Message',
                    'type'          => 'textarea',
                    'css'           => 'width:500px;',
                    'default'       => 'Your Payment Gateway Description',
                    'description'   => 'The message which you want it to appear to the customer in the checkout page.',
                ),
                // 新增后台配置项:外部支付地址、回调验签密钥
                'external_pay_url' => array(
                    'title'         => '外部支付站点地址',
                    'type'          => 'text',
                    'description'   => '用户提交订单后跳转的外部支付页完整URL',
                    'desc_tip'      => true,
                ),
                'callback_key' => array(
                    'title'         => '回调验签密钥',
                    'type'          => 'password',
                    'description'   => '用于校验回调请求合法性的自定义密钥,需和外部支付站点保持一致',
                    'desc_tip'      => true,
                )
            );
        }

        public function payment_fields(){
            ?>
            <fieldset>
                <p class="form-row form-row-wide">
                    <?php echo esc_attr($this->description); ?>
                </p>                        
                <div class="clear"></div>
            </fieldset>
            <?php
        }

        // 实现订单提交支付处理方法
        public function process_payment( $order_id ) {
            $order = wc_get_order( $order_id );
            // 1. 组装需要传递给外部站点的参数
            $product_ids = array();
            foreach ( $order->get_items() as $item ) {
                $product_ids[] = $item->get_product_id();
            }
            $pay_params = array(
                'order_id'      => $order_id,
                'product_ids'   => implode(',', $product_ids),
                'cart_id'       => $order->get_meta('_cart_hash', true), // 购物车唯一标识
                'total_amount'  => $order->get_total(),
                'callback_url'  => WC()->api_request_url('wc_custom_pg_callback'),
                'return_url'    => $this->get_return_url( $order ), // 支付完成后用户跳转回的站点地址
            );
            // 生成签名:参数按key排序拼接后加密钥做md5,防止参数篡改
            ksort($pay_params);
            $sign_str = http_build_query($pay_params) . $this->callback_key;
            $pay_params['sign'] = md5($sign_str);

            // 2. 更新订单状态为待支付,清空购物车
            $order->update_status('wc-pending', '等待外部支付站点确认支付');
            WC()->cart->empty_cart();

            // 3. 返回跳转地址,WooCommerce自动执行跳转
            return array(
                'result'   => 'success',
                'redirect' => add_query_arg($pay_params, $this->external_pay_url)
            );
        }

        // 实现支付回调处理方法
        public function handle_payment_callback() {
            // 1. 获取回调参数
            $params = $_POST;
            if ( empty($params) ) {
                wp_die('无效请求', 'Invalid Request', array('response' => 400));
            }

            // 2. 校验签名
            $client_sign = $params['sign'];
            unset($params['sign']);
            ksort($params);
            $sign_str = http_build_query($params) . $this->callback_key;
            $server_sign = md5($sign_str);
            if ( $client_sign !== $server_sign ) {
                wc_get_logger()->error('自定义支付回调验签失败', array('source' => 'wc_custom_pg', 'params' => $params));
                wp_die('签名校验失败', 'Sign Error', array('response' => 403));
            }

            // 3. 校验订单和金额
            $order = wc_get_order( intval($params['order_id']) );
            if ( !$order || $order->get_payment_method() !== $this->id ) {
                wp_die('订单不存在', 'Order Not Found', array('response' => 404));
            }
            // 已经处理过的订单直接返回成功,避免重复回调
            if ( $order->is_paid() ) {
                echo 'success';
                exit;
            }
            if ( floatval($params['total_amount']) !== floatval($order->get_total()) ) {
                $order->update_status('wc-failed', '支付金额不匹配,回调金额:' . $params['total_amount']);
                wp_die('金额校验失败', 'Amount Error', array('response' => 400));
            }

            // 4. 根据支付结果更新订单
            if ( $params['pay_status'] === 'success' ) {
                // 支付成功:更新订单为处理中状态,记录支付信息,自动触发库存扣减、支付成功邮件
                $order->payment_complete( $params['trade_no'] ?? '' ); // 传入外部支付流水号
                $order->add_order_note('支付成功,外部交易号:' . ($params['trade_no'] ?? '未知'));
                echo 'success';
            } else {
                // 支付失败
                $order->update_status('wc-failed', '支付失败,原因:' . ($params['fail_reason'] ?? '未知'));
                echo 'fail';
            }
            exit;
        }
    }
}

注意事项

  • 外部支付站点回调时必须原样回传你传过去的所有业务参数,加上支付状态、交易号、签名,否则验签会失败
  • 回调地址不需要做登录校验,WooCommerce的API钩子默认支持匿名访问
  • 所有回调异常都会存在WooCommerce日志里,后台可以在「WooCommerce-状态-日志」中选择wc_custom_pg源查看排错

内容的提问来源于stack exchange,提问作者ibrar Adil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 16:30:44