WordPress自定义插件PHP Session报错:干扰REST API及回环请求
解决WordPress插件PHP Session与REST API冲突问题
问题根源
当前代码在init全局钩子中启动Session,导致所有请求(包括REST API、后台loopback请求)都会创建Session,触发冲突报错。而使用read_and_close参数会直接关闭Session,无法保留表单步骤数据。
解决方案
1. 精准控制Session启动时机
只在前端表单页面和插件自身AJAX请求中启动Session,排除REST API、后台、无关AJAX请求。
修改插件主类代码:
class WP_Oscar { public function __construct() { require_once XHE_HCV_DIR . 'includes/class-email.php'; require_once XHE_HCV_DIR . 'includes/class-ajax.php'; require_once XHE_HCV_DIR . 'includes/class-register-users.php'; // 移除全局init钩子的session_start,改为按需启动 // add_action('init', array( $this, 'session_start' ) ); add_action( 'wp_logout', array( $this, 'session_end' ) ); add_action( 'wp_login',array( $this, 'session_end' ) ); // 保留其他钩子 add_shortcode( 'oscar_appointment', array($this, 'display_shortcode') ); add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ), 999 ); add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts_admin' ), 999 ); add_action('admin_menu', array($this, 'admin_menu')); add_action('admin_init', array($this, 'register_settings')); // 添加请求结束时关闭Session的钩子 add_action('shutdown', array($this, 'session_close')); } // 新增判断是否为REST请求的辅助方法 private function is_rest_request() { return defined('REST_REQUEST') && REST_REQUEST; } public function session_start() { // 仅在非后台、非REST、非无关AJAX的场景下启动Session if (session_status() == PHP_SESSION_NONE && !headers_sent()) { // 场景1:前端表单页面(包含插件短码) if (!is_admin() && !$this->is_rest_request() && !wp_doing_ajax()) { global $post; if (is_a($post, 'WP_Post') && has_shortcode($post->post_content, 'oscar_appointment')) { session_start(); } } // 场景2:插件自身的AJAX请求(替换为你的AJAX动作名) if (wp_doing_ajax()) { $allowed_ajax_actions = array('oscar_form_step_submit', 'oscar_get_available_times'); // 示例动作名 if (isset($_POST['action']) && in_array($_POST['action'], $allowed_ajax_actions)) { session_start(); } } } } public function session_end() { if (session_status() == PHP_SESSION_ACTIVE) { session_destroy(); } } public function session_close() { if (session_status() == PHP_SESSION_ACTIVE) { session_write_close(); } } private function display_form() { // 进入表单页面时主动启动Session $this->session_start(); // 原display_form代码保持不变 $steps = array( 'init' => XHE_HCV_DIR . 'templates/html-init.php', 'register' => XHE_HCV_DIR . 'templates/html-new-client.php', 'hin' => XHE_HCV_DIR . 'templates/html-hin.php', 'email' => XHE_HCV_DIR . 'templates/html-email.php', 'booking_time' => XHE_HCV_DIR . 'templates/html-booking-time.php', 'confirm' => XHE_HCV_DIR . 'templates/html-confirm.php' ); echo '<script src="https://www.google.com/recaptcha/api.js" async defer></script>'; $xhe_hcv_term_pageid = $this->get_option_value('oscar_emr_plugin_options', 'oa_oscar_emr_xhe_hcv_term_pageid'); if( $xhe_hcv_term_pageid ) { $term_page = get_post( absint($xhe_hcv_term_pageid) ); if( ! empty($term_page->post_content) ) { printf( '<div id="openTermModal" class="venobox-modal">%s</div>', $term_page->post_content ); } } // ... 后续代码 } // 其他方法保持不变 }
2. 表单提交后清理Session
在表单最终确认提交的处理逻辑中,完成数据存储后主动销毁Session,避免残留:
// 示例:在确认提交的函数中添加 public function process_booking_confirm() { // 处理表单数据存储逻辑... // 清理Session $this->session_end(); }
3. AJAX请求中的Session处理
在class-ajax.php中,处理插件AJAX动作时,确保Session正确读写:
// 示例AJAX处理函数 public function handle_form_step() { // 先启动Session if (session_status() == PHP_SESSION_NONE && !headers_sent()) { session_start(); } // 处理表单步骤数据,写入Session $_SESSION['form_step_data']['current_step'] = $_POST['step']; $_SESSION['form_step_data']['selected_time'] = $_POST['time']; // 完成后关闭Session session_write_close(); // 返回响应 wp_send_json_success('步骤保存成功'); }
关键说明
- 避免全局启动Session,仅在需要的场景初始化,从根源解决REST API冲突
- 使用
shutdown钩子在请求结束时统一关闭Session,释放资源 - AJAX请求需单独判断动作,确保只有插件自身的AJAX才启动Session
- 表单完成后及时销毁Session,避免用户数据残留
内容的提问来源于stack exchange,提问作者ysq74
相关产品推荐
相关产品推荐

