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
相关产品推荐
相关产品推荐

