WooCommerce自定义支付网关外部跳转传参与回调实现方案
WooCommerce自定义支付网关跳转+回调实现方案
你现有代码已经完成了支付网关的基础挂载和后台配置,只需要补充订单提交跳转逻辑和回调验签更新订单逻辑即可,核心用到的WooCommerce内置能力不需要额外注册自定义路由,全部基于支付网关抽象类的规范和官方钩子实现。
核心实现逻辑说明
1. 订单提交跳转部分
不需要额外找提交订单的钩子,直接在自定义网关类中实现process_payment($order_id)方法即可,用户选择该支付方式点击提交订单时,WooCommerce会自动调用这个方法:
- 方法内首先获取订单对象,将订单初始化为待支付状态
- 组装需要传递给外部支付站点的参数:订单ID、商品ID集合、购物车hash(即需求中提到的购物车ID,存在订单
_cart_hashmeta中)、订单总金额、回调地址、验签串 - 清空用户当前购物车,返回跳转指令,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
相关产品推荐
相关产品推荐

