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

WordPress执行do_action后wp_send_json无法返回前端响应

问题:Bookly预约保存后Ajax无响应,页面持续加载

我需要和第三方预约插件Bookly交互发送短信。之前直接修改Bookly的Ajax.php实现了短信发送,但为了后台管控流程,开发了外部插件。在Bookly的Ajax.php中添加了自定义钩子bookly_appointment_saved并传入预约信息数组,外部插件能成功捕获钩子且短信正常发送,但Bookly的Ajax.php无法向前端返回响应,页面一直处于加载状态。


相关代码

Bookly的Ajax.php核心方法

/**
 * Save cart appointments.
 */
public static function saveAppointment()
{
    $userData = new Lib\UserBookingData( self::parameter( 'form_id' ) );

    if ( $userData->load() ) {
        $failed_cart_key = $userData->cart->getFailedKey();
        if ( $failed_cart_key === null ) {
            $cart_info = $userData->cart->getInfo();
            $is_payment_disabled = Lib\Config::paymentStepDisabled();
            $skip_payment = BookingProxy\CustomerGroups::getSkipPayment( $userData->getCustomer() );
            $gateways = self::getGateways( $userData, clone $cart_info );

            if ( $is_payment_disabled || isset( $gateways['local'] ) || $cart_info->getPayNow() <= 0 || $skip_payment ) {
                // Handle coupon.
                $coupon = $userData->getCoupon();
                if ( $coupon ) {
                    $coupon->claim()->save();
                }
                // Handle payment.
                $payment = null;
                if ( ! $is_payment_disabled && ! $skip_payment ) {
                    if ( $cart_info->getTotal() <= 0 ) {
                        if ( $cart_info->withDiscount() ) {
                            $payment = new Lib\Entities\Payment();
                            $payment
                                ->setType( Lib\Entities\Payment::TYPE_FREE )
                                ->setStatus( Lib\Entities\Payment::STATUS_COMPLETED )
                                ->setPaidType( Lib\Entities\Payment::PAY_IN_FULL )
                                ->setTotal( 0 )
                                ->setPaid( 0 )
                                ->save();
                        }
                    } else {
                        $payment = new Lib\Entities\Payment();
                        $status = Lib\Entities\Payment::STATUS_PENDING;
                        $type = Lib\Entities\Payment::TYPE_LOCAL;
                        $paid = 0;
                        foreach ( $gateways as $gateway => $data ) {
                            if ( $data['pay'] == 0 ) {
                                $status = Lib\Entities\Payment::STATUS_COMPLETED;
                                $type = Lib\Entities\Payment::TYPE_FREE;
                                $cart_info->setGateway( $gateway );
                                $payment->setGatewayPriceCorrection( $cart_info->getPriceCorrection() );
                                break;
                            }
                        }

                        if ( $status !== Lib\Entities\Payment::STATUS_COMPLETED ) {
                            $gift_card = $userData->getGiftCard();
                            if ( $gift_card ) {
                                $type = Lib\Entities\Payment::TYPE_CLOUD_GIFT;
                                $cart_info->setGateway( $type );
                                if ( $gift_card->getBalance() >= $cart_info->getPayNow() ) {
                                    $status = Lib\Entities\Payment::STATUS_COMPLETED;
                                    $paid = $cart_info->getPayNow();
                                    $gift_card->charge( $paid )->save();
                                    $payment->setGatewayPriceCorrection( $cart_info->getPriceCorrection() );
                                }
                            }
                        }

                        $payment
                            ->setType( $type )
                            ->setStatus( $status )
                            ->setPaidType( Lib\Entities\Payment::PAY_IN_FULL )
                            ->setTotal( $cart_info->getTotal() )
                            ->setTax( $cart_info->getTotalTax() )
                            ->setPaid( $paid )
                            ->save();
                    }
                }
                // Save cart.
                $order = $userData->save( $payment );
                if ( $payment !== null ) {
                    $payment->setDetailsFromOrder( $order, $cart_info )->save();
                }
                // Send notifications.
                Lib\Notifications\Cart\Sender::send( $order );
                $response = array(
                    'success' => true,
                );
            } else {
                $response = array(
                    'success' => false,
                    'error' => Errors::PAY_LOCALLY_NOT_AVAILABLE,
                );
            }
        } else {
            $response = array(
                'success' => false,
                'failed_cart_key' => $failed_cart_key,
                'error' => Errors::CART_ITEM_NOT_AVAILABLE,
            );
        }

        //Custom hook
        $user_appointed=$userData->getData();
        do_action('bookly_appointment_saved',
            $appointment=[
                'date'=>date("d/m/Y", strtotime($user_appointed['slots'][0][2]) ),
                'time'=>date("H:i", strtotime($user_appointed['slots'][0][2]) ),
                'full_name'=>$user_appointed['full_name']==''?$user_appointed['first_name'].' '.$user_appointed['last_name']:$user_appointed['full_name'],
                'service_name'=>$userData->cart->getItemsTitle(),

            ]
        );
        // end of hook


        $userData->sessionSave();
        wp_send_json( $response );
        
    }

    Errors::sendSessionError();
}

自定义短信发送插件(custom-sms-sender-plugin.php)

add_action('bookly_appointment_saved','send_sms');
function send_sms($appointment){
    
    $phone = "66666666666";
    $message="New appointment - ".$appointment['full_name']." Service: ".$appointment['service_name']." Date: ".$appointment['date']." Time:".$appointment['time'];
    $message = urlencode($message);


    $url= "//request url with parameters";

                    
    $request = wp_remote_get($url);
    if ($request['body'] !=30 || $request['body'] !=20 || $request['body'] !=40 || $request['body'] !=50 || $request['body'] != 51 || $request['body'] != 70 || $request['body'] != 85) {
        write_log("SENT - SMS Code : ".explode(" ",$request['body'])[1]);
    } else {
        write_log("ERROR - Code : ".$request['body']);
    }
    
}

解决方案

问题核心是wp_remote_get()是同步HTTP请求,会阻塞当前Ajax流程,直到短信服务商返回响应。如果服务商接口响应慢或超时,Bookly的Ajax就无法及时执行wp_send_json($response),导致页面持续加载。

以下是两种异步处理方案:

方案1:启用异步HTTP请求

修改自定义插件中的wp_remote_get调用,添加blocking参数让请求异步执行,不阻塞主流程:

add_action('bookly_appointment_saved','send_sms');
function send_sms($appointment){
    
    $phone = "66666666666";
    $message="New appointment - ".$appointment['full_name']." Service: ".$appointment['service_name']." Date: ".$appointment['date']." Time:".$appointment['time'];
    $message = urlencode($message);

    $url= "//request url with parameters";

    // 异步请求配置
    $args = array(
        'blocking' => false, // 关键:不阻塞主流程
        'timeout' => 5,      // 设置超时时间,避免占用资源
    );
                    
    wp_remote_get($url, $args);
    // 异步请求无法立即获取响应,仅记录请求发起状态
    error_log("SMS request initiated for appointment: ".$appointment['full_name']);
}

方案2:使用WP Cron后台执行

将短信发送任务交给WP Cron,让WordPress在后台异步执行,完全不影响主Ajax流程:

add_action('bookly_appointment_saved','schedule_sms_send');
function schedule_sms_send($appointment){
    // 调度一个立即执行的一次性任务
    wp_schedule_single_event(time(), 'send_sms_cron_job', array($appointment));
}

// 注册Cron任务钩子
add_action('send_sms_cron_job','send_sms');
function send_sms($appointment){
    
    $phone = "66666666666";
    $message="New appointment - ".$appointment['full_name']." Service: ".$appointment['service_name']." Date: ".$appointment['date']." Time:".$appointment['time'];
    $message = urlencode($message);

    $url= "//request url with parameters";

    $request = wp_remote_get($url);
    if ($request['body'] !=30 || $request['body'] !=20 || $request['body'] !=40 || $request['body'] !=50 || $request['body'] != 51 || $request['body'] != 70 || $request['body'] != 85) {
        error_log("SENT - SMS Code : ".explode(" ",$request['body'])[1]);
    } else {
        error_log("ERROR - Code : ".$request['body']);
    }
}

额外注意事项

  • 替换自定义的write_log为WordPress原生error_log()函数,避免未定义函数报错。
  • 确保WP Cron功能正常(部分主机可能禁用Cron,需手动开启或使用替代方案)。

内容的提问来源于stack exchange,提问作者Şahin Yıldırım

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 05:50:27