基于Contact Form7与OpenAI API的WordPress博客生成插件故障排查
我正在开发一款WordPress插件,功能是从Contact Form 7表单提取信息,发送到OpenAI API,再把生成的文本返回给用户查看。这是我第一次开发WordPress插件,按指导写完代码后,点击生成按钮没有内容显示,通过开发者工具发现API请求返回text: null,求解决。
相关代码
openai-blog-generator.php
/* Plugin Name: AI Blog Generator Description: Generates blog posts using OpenAI's GPT-3 model Version: 1.0 Author: trobanko */ // Define constants for OpenAI API define('OPENAI_API_KEY', 'your_openai_api_key'); define('OPENAI_API_URL', 'https://api.openai.com/v1/engines'); // Add shortcode for Contact Form 7 form add_shortcode('ai_blog_generator_form', 'ai_blog_generator_form_shortcode'); function ai_blog_generator_form_shortcode() { error_log("1"); ob_start(); ?> <div class="ai-blog-generator-form"> <?php echo do_shortcode('[contact-form-7 id="10" title="Contact form 1"]'); ?> </div> <?php return ob_get_clean(); } // Add custom endpoint for generating blog post add_action('rest_api_init', 'ai_blog_generator_register_endpoint'); function ai_blog_generator_register_endpoint() { error_log("2"); register_rest_route('ai-blog-generator/v1', '/generate-blog', array( 'methods' => 'POST', 'callback' => 'ai_blog_generator_generate_blog', )); } // Callback function for generating blog post function ai_blog_generator_generate_blog($request) { error_log("3"); $params = $request->get_params(); // Get input data from form fields $topic = sanitize_text_field($params['blog_topic']); $style = sanitize_text_field($params['writing_style']); $outline = sanitize_textarea_field($params['outline']); error_log("Input Data: Topic: " . $topic . ", Writing Style: " . $style . ", Outline: " . $outline); // Define prompt for OpenAI API $prompt = "Blog topic: $topic Writing style: $style Outline: $outline Generate blog post:"; error_log("Prompt: " . $prompt); // Set up API request $data = array( 'prompt' => $prompt, 'temperature' => 0.5, 'max_tokens' => 500, 'n' => 1, ); $args = array( 'headers' => array( 'Content-Type' => 'application/json', 'Authorization' => 'Bearer ' . OPENAI_API_KEY, ), 'body' => json_encode($data), 'timeout' => 30, ); // Send request to OpenAI API error_log("Sending request to OpenAI API..."); $response = wp_remote_post(OPENAI_API_URL . '/davinci-003/completions', $args); error_log("Received response from OpenAI API"); // Parse response if (is_wp_error($response)) { $error_message = $response->get_error_message(); error_log("API Error: " . $error_message); return new WP_Error('api_error', $error_message, array('status' => 500)); } else { $body = wp_remote_retrieve_body($response); $json = json_decode($body, true); $text = $json['choices'][0]['text']; error_log("Generated text: " . $text); return array('text' => $text); } } // Add script for generating blog post add_action('wp_enqueue_scripts', 'ai_blog_generator_enqueue_scripts'); function ai_blog_generator_enqueue_scripts() { error_log("4"); wp_enqueue_script('ai-blog-generator', plugins_url('/js/ai-blog-generator.js', __FILE__), array('jquery'), '1.0', true); wp_localize_script('ai-blog-generator', 'aiBlogGeneratorSettings', array( 'apiUrl' => esc_url_raw(rest_url('ai-blog-generator/v1/generate-blog')), 'nonce' => wp_create_nonce('wp_rest'), )); } // Add CSS for Contact Form 7 form add_action('wp_enqueue_scripts', 'ai_blog_generator_enqueue_styles'); function ai_blog_generator_enqueue_styles() { error_log("5"); wp_enqueue_style('ai-blog-generator', plugins_url('/css/ai-blog-generator.css', __FILE__), array(), '1.0', 'all'); } // Add settings link to plugin page add_filter('plugin_action_links_' . plugin_basename(__FILE__), 'ai_blog_generator_settings_link'); function ai_blog_generator_settings_link($links) { $settings_link = '<a href="admin.php?page=ai-blog-generator-settings">Settings</a>'; array_push($links, $settings_link); return $links; } // Register settings page add_action('admin_menu', 'ai_blog_generator_settings_page'); function ai_blog_generator_settings_page() { add_menu_page('AI Blog Generator Settings', 'AI Blog Generator', 'manage_options', 'ai-blog-generator-settings', 'ai_blog_generator_settings'); } // Display settings page function ai_blog_generator_settings() { ?> <div class="wrap"> <h1>AI Blog Generator Settings</h1> <form method="post" action="options.php"> <?php settings_fields('ai_blog_generator_options'); do_settings_sections('ai_blog_generator_options'); submit_button(); ?> </form> </div> <?php } // Register settings add_action('admin_init', 'ai_blog_generator_register_settings'); function ai_blog_generator_register_settings() { register_setting('ai_blog_generator_options', 'ai_blog_generator_api_key'); add_settings_section('ai_blog_generator_api_settings', 'OpenAI API Settings', 'ai_blog_generator_api_settings_callback', 'ai_blog_generator_options'); add_settings_field('ai_blog_generator_api_key', 'API Key', 'ai_blog_generator_api_key_callback', 'ai_blog_generator_options', 'ai_blog_generator_api_settings'); } // Display API settings section function ai_blog_generator_api_settings_callback() { echo '<p>Enter your OpenAI API key below:</p>'; } // Display API key field function ai_blog_generator_api_key_callback() { $api_key = get_option('ai_blog_generator_api_key'); echo '<input type="text" name="ai_blog_generator_api_key" value="' . esc_attr($api_key) . '" />'; } // Add API key to API requests add_filter('http_request_args', 'ai_blog_generator_add_api_key', 10, 2); function ai_blog_generator_add_api_key($args, $url) { if (strpos($url, 'api.openai.com') !== false) { $api_key = get_option('ai_blog_generator_api_key'); if ($api_key) { $args['headers']['Authorization'] = 'Bearer ' . $api_key; } } return $args; }
ai-blog-generator.js
jQuery(document).ready(function($) { $('#generate-blog').on('submit', function(event) { event.preventDefault(); console.log('Form submitted'); // Get form data var formData = $(this).serialize(); console.log('Form data:', formData); // Send AJAX request $.ajax({ url: ai_blog_generator_params.endpoint, type: 'POST', data: formData, beforeSend: function(xhr) { xhr.setRequestHeader('X-WP-Nonce', ai_blog_generator_params.nonce); }, success: function(response) { console.log('API response:', response); var text = response.text; if (text) { console.log('Generated text:', text); $('#blog-post').html(text); } else { console.log('Error: Empty response'); $('#blog-post').html('Error: Empty response'); } }, error: function(jqXHR, textStatus, errorThrown) { console.log('AJAX error:', jqXHR.responseText); $('#blog-post').html('Error: ' + jqXHR.responseText); } }); }); });
ai-blog-generator-rest-api.php
/** * Register REST API endpoint for generating blog posts. */ // Exit if accessed directly. if (! defined('ABSPATH')) { exit; } class AI_Blog_Generator_REST_API { /** * Initialize REST API endpoint for generating blog posts. */ public function __construct() { add_action('rest_api_init', array($this, 'register_routes')); } /** * Register REST API endpoint for generating blog posts. */ public function register_routes() { register_rest_route( 'ai-blog-generator/v1', '/generate-blog', array( 'methods' => 'POST', 'callback' => array($this, 'generate_blog'), 'permission_callback' => array($this, 'permission_callback') ) ); } /** * Check if user has permissions to access the endpoint. */ public function permission_callback() { // Add log message error_log('Permission check for AI Blog Generator REST API.'); return current_user_can('manage_options'); } /** * Generate blog post using OpenAI's GPT-3 model. */ public function generate_blog($request) { // Add log message error_log('Generate blog endpoint called for AI Blog Generator REST API.'); $params = $request->get_params(); // Get input data from form fields. $topic = sanitize_text_field($params['blog_topic']); $style = sanitize_text_field($params['writing_style']); $outline = sanitize_textarea_field($params['outline']); // Define prompt for OpenAI API. $prompt = "Blog topic: $topic Writing style: $style Outline: $outline Generate blog post:"; // Set up API request. $data = array( 'prompt' => $prompt, 'temperature' => 0.5, 'max_tokens' => 500, 'n' => 1, ); $args = array( 'headers' => array( 'Content-Type' => 'application/json', 'Authorization' => 'Bearer ' . OPENAI_API_KEY, ), 'body' => json_encode($data), 'timeout' => 30, ); // Send request to OpenAI API. $response = wp_remote_post(OPENAI_API_URL . '/davinci-003/completions', $args); // Parse response. if (is_wp_error($response)) { $error_message = $response->get_error_message(); // Add log message error_log('Error occurred in AI Blog Generator REST API: ' . $error_message); return new WP_Error('api_error', $error_message, array('status' => 500)); } else { $body = wp_remote_retrieve_body($response); $json = json_decode($body, true); $text = $json['choices'][0]['text']; // Add log message error_log('AI Blog Generator REST API: Generated text: ' . $text); return array('text' => $text); } } } new AI_Blog_Generator_REST_API();
1. 重复注册REST端点导致冲突
代码同时在openai-blog-generator.php和ai-blog-generator-rest-api.php中注册了同一个ai-blog-generator/v1/generate-blog端点,回调执行逻辑混乱。
修复: 删除openai-blog-generator.php中从add_action('rest_api_init', ...)到ai_blog_generator_generate_blog函数的全部代码。
2. JavaScript变量名不匹配
PHP中通过wp_localize_script注册的变量是aiBlogGeneratorSettings,但JS中使用ai_blog_generator_params调用,导致无法获取正确的API地址和Nonce。
修复: 修改ai-blog-generator.js中的变量名:
// 替换原AJAX配置中的url和nonce参数 url: aiBlogGeneratorSettings.apiUrl, beforeSend: function(xhr) { xhr.setRequestHeader('X-WP-Nonce', aiBlogGeneratorSettings.nonce); },
3. OpenAI API密钥未正确读取
类中的API请求直接使用常量OPENAI_API_KEY,但设置页面的密钥存储在ai_blog_generator_api_key选项中,导致设置无效。
修复: 修改ai-blog-generator-rest-api.php中的API请求头部:
// 替换原请求参数中的Authorization部分 $api_key = get_option('ai_blog_generator_api_key'); $args = array( 'headers' => array( 'Content-Type' => 'application/json', 'Authorization' => 'Bearer ' . $api_key, ), 'body' => json_encode($data), 'timeout' => 30, );
同时删除openai-blog-generator.php中的define('OPENAI_API_KEY', 'your_openai_api_key');代码。
4. 未处理OpenAI API错误响应
当前代码直接读取$json['choices'][0]['text'],如果API返回错误(如密钥无效、额度不足),会导致$text为null。
修复: 在ai-blog-generator-rest-api.php的响应解析部分添加错误判断:
} else { $body = wp_remote_retrieve_body($response); $json = json_decode($body, true); // 检查API错误 if (isset($json['error'])) { error_log('OpenAI API Error: ' . $json['error']['message']); return new WP_Error('openai_error', $json['error']['message'], array('status' => 400)); } // 检查响应结构 if (!isset($json['choices'][0]['text'])) { error_log('OpenAI API returned invalid response: ' . $body); return new WP_Error('invalid_response', 'Invalid response from OpenAI API', array('status' => 500)); } $text = $json['choices'][0]['text']; error_log('AI Blog Generator REST API: Generated text: ' . $text); return array('text' => $text); }
5. 权限限制过严(可选)
当前权限回调要求用户具备manage_options权限,普通用户无法使用。如需开放给更多用户,可修改:
public function permission_callback() { // 允许所有登录用户访问 return is_user_logged_in(); }
内容的提问来源于stack exchange,提问作者Trobanko

