添加完整的AI SEO助手WordPress插件,主要功能包括: - 集成Dify API自动生成SEO优化的标题、描述和关键词 - 支持导航主题的自定义字段适配 - 提供管理界面设置API和文章类型支持 - 包含前端SEO标签自动应用功能 - 添加详细的测试和调试功能
503 lines
18 KiB
PHP
503 lines
18 KiB
PHP
<?php
|
||
/**
|
||
* Plugin Name: AI SEO 助手
|
||
* Plugin URI: https://ckk.photo8.site/Photo8/wordpress-plugins
|
||
* Description: 使用AI自动生成SEO TDK内容的WordPress插件,集成Dify API
|
||
* Version: 1.0.7
|
||
* Author: SnowZ
|
||
* License: GPL v2 or later
|
||
* Text Domain: ai-seo-generator
|
||
*/
|
||
|
||
// 防止直接访问
|
||
if (!defined('ABSPATH')) {
|
||
exit;
|
||
}
|
||
|
||
// 定义插件常量
|
||
define('AI_SEO_PLUGIN_URL', plugin_dir_url(__FILE__));
|
||
define('AI_SEO_PLUGIN_PATH', plugin_dir_path(__FILE__));
|
||
define('AI_SEO_VERSION', '1.0.0');
|
||
|
||
// 加载安装脚本
|
||
require_once AI_SEO_PLUGIN_PATH . 'install.php';
|
||
|
||
// 加载测试功能(仅在管理后台)
|
||
if (is_admin()) {
|
||
require_once AI_SEO_PLUGIN_PATH . 'test/api-test.php';
|
||
}
|
||
|
||
/**
|
||
* 主插件类
|
||
*/
|
||
class AiSeoGenerator {
|
||
|
||
/**
|
||
* 构造函数 - 初始化插件
|
||
*/
|
||
public function __construct() {
|
||
add_action('init', array($this, 'init'));
|
||
register_activation_hook(__FILE__, array($this, 'activate'));
|
||
register_deactivation_hook(__FILE__, array($this, 'deactivate'));
|
||
}
|
||
|
||
/**
|
||
* 插件初始化
|
||
*/
|
||
public function init() {
|
||
// 加载文本域
|
||
load_plugin_textdomain('ai-seo-generator', false, dirname(plugin_basename(__FILE__)) . '/languages');
|
||
|
||
// 添加管理菜单
|
||
add_action('admin_menu', array($this, 'add_admin_menu'));
|
||
|
||
// 添加编辑页面的meta box
|
||
add_action('add_meta_boxes', array($this, 'add_meta_boxes'));
|
||
|
||
// 保存文章时的钩子
|
||
add_action('save_post', array($this, 'save_post_meta'));
|
||
|
||
// 添加AJAX处理
|
||
add_action('wp_ajax_generate_seo_content', array($this, 'ajax_generate_seo_content'));
|
||
|
||
// 加载管理页面样式和脚本
|
||
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
|
||
|
||
// 前端钩子 - 修改页面标题和meta标签
|
||
add_filter('wp_title', array($this, 'custom_wp_title'), 10, 2);
|
||
add_action('wp_head', array($this, 'add_meta_tags'));
|
||
}
|
||
|
||
/**
|
||
* 插件激活时执行
|
||
*/
|
||
public function activate() {
|
||
// 创建数据库表或设置默认选项
|
||
$this->create_options();
|
||
}
|
||
|
||
/**
|
||
* 插件停用时执行
|
||
*/
|
||
public function deactivate() {
|
||
// 清理工作
|
||
}
|
||
|
||
/**
|
||
* 创建默认选项
|
||
*/
|
||
private function create_options() {
|
||
add_option('ai_seo_api_key', '');
|
||
add_option('ai_seo_api_url', '');
|
||
}
|
||
|
||
/**
|
||
* 添加管理菜单
|
||
*/
|
||
public function add_admin_menu() {
|
||
add_options_page(
|
||
'AI SEO Generator 设置',
|
||
'AI SEO Generator',
|
||
'manage_options',
|
||
'ai-seo-generator',
|
||
array($this, 'admin_page')
|
||
);
|
||
|
||
// 添加测试页面子菜单
|
||
add_submenu_page(
|
||
'options-general.php',
|
||
'AI SEO 测试',
|
||
'AI SEO 测试',
|
||
'manage_options',
|
||
'ai-seo-test',
|
||
array($this, 'test_page')
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 管理页面内容
|
||
* 处理设置保存,包括API配置和支持的文章类型
|
||
*/
|
||
public function admin_page() {
|
||
if (isset($_POST['submit'])) {
|
||
// 保存API设置
|
||
update_option('ai_seo_api_key', sanitize_text_field($_POST['api_key']));
|
||
update_option('ai_seo_api_url', esc_url_raw($_POST['api_url']));
|
||
|
||
// 保存支持的文章类型设置
|
||
$supported_post_types = array();
|
||
if (isset($_POST['supported_post_types']) && is_array($_POST['supported_post_types'])) {
|
||
// 获取所有公开的post类型进行验证
|
||
$all_post_types = get_post_types(array('public' => true), 'names');
|
||
foreach ($_POST['supported_post_types'] as $post_type) {
|
||
$post_type = sanitize_text_field($post_type);
|
||
// 只保存有效的公开post类型
|
||
if (in_array($post_type, $all_post_types)) {
|
||
$supported_post_types[] = $post_type;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 如果没有选择任何类型,默认支持post和page
|
||
if (empty($supported_post_types)) {
|
||
$supported_post_types = array('post', 'page');
|
||
}
|
||
|
||
update_option('ai_seo_supported_post_types', $supported_post_types);
|
||
|
||
echo '<div class="notice notice-success"><p>设置已保存!支持的文章类型:' . implode(', ', $supported_post_types) . '</p></div>';
|
||
}
|
||
|
||
$api_key = get_option('ai_seo_api_key', '');
|
||
$api_url = get_option('ai_seo_api_url', '');
|
||
|
||
include AI_SEO_PLUGIN_PATH . 'admin/settings.php';
|
||
}
|
||
|
||
/**
|
||
* 测试页面内容
|
||
*/
|
||
public function test_page() {
|
||
if (!class_exists('AiSeoApiTest')) {
|
||
echo '<div class="wrap"><h1>测试功能不可用</h1><p>测试类未加载。</p></div>';
|
||
return;
|
||
}
|
||
|
||
echo '<div class="wrap">';
|
||
echo '<h1>🧪 AI SEO Generator 测试</h1>';
|
||
echo '<p>此页面用于测试API连接和功能验证。</p>';
|
||
|
||
if (isset($_POST['run_test'])) {
|
||
$tester = new AiSeoApiTest();
|
||
echo $tester->generate_test_report();
|
||
} else {
|
||
echo '<form method="post">';
|
||
echo '<p><button type="submit" name="run_test" class="button button-primary">🚀 运行测试</button></p>';
|
||
echo '</form>';
|
||
|
||
echo '<div class="ai-seo-test-info">';
|
||
echo '<h3>测试内容包括:</h3>';
|
||
echo '<ul>';
|
||
echo '<li>✅ API连接测试</li>';
|
||
echo '<li>✅ SEO内容生成测试</li>';
|
||
echo '<li>✅ 系统环境检查</li>';
|
||
echo '<li>✅ 插件配置验证</li>';
|
||
echo '</ul>';
|
||
echo '</div>';
|
||
}
|
||
|
||
echo '</div>';
|
||
}
|
||
|
||
/**
|
||
* 添加meta boxes到编辑页面
|
||
* 支持所有公开的post类型,包括自定义post类型
|
||
*/
|
||
public function add_meta_boxes() {
|
||
// 获取所有公开的post类型
|
||
$post_types = get_post_types(array('public' => true), 'names');
|
||
|
||
// 从设置中获取支持的post类型,如果没有设置则使用所有公开类型
|
||
$supported_post_types = get_option('ai_seo_supported_post_types', $post_types);
|
||
|
||
// 确保支持的类型都是公开的
|
||
$supported_post_types = array_intersect($supported_post_types, $post_types);
|
||
|
||
// 为每个支持的post类型添加meta box
|
||
foreach ($supported_post_types as $post_type) {
|
||
add_meta_box(
|
||
'ai-seo-generator',
|
||
'AI SEO Generator',
|
||
array($this, 'meta_box_callback'),
|
||
$post_type,
|
||
'normal',
|
||
'high'
|
||
);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* Meta box回调函数
|
||
*/
|
||
public function meta_box_callback($post) {
|
||
wp_nonce_field('ai_seo_meta_box', 'ai_seo_meta_box_nonce');
|
||
|
||
$seo_title = get_post_meta($post->ID, '_ai_seo_title', true);
|
||
$seo_description = get_post_meta($post->ID, '_ai_seo_description', true);
|
||
$seo_keywords = get_post_meta($post->ID, '_ai_seo_keywords', true);
|
||
|
||
include AI_SEO_PLUGIN_PATH . 'admin/meta-box.php';
|
||
}
|
||
|
||
/**
|
||
* 保存文章meta数据
|
||
*/
|
||
public function save_post_meta($post_id) {
|
||
if (!isset($_POST['ai_seo_meta_box_nonce']) || !wp_verify_nonce($_POST['ai_seo_meta_box_nonce'], 'ai_seo_meta_box')) {
|
||
return;
|
||
}
|
||
|
||
if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) {
|
||
return;
|
||
}
|
||
|
||
if (!current_user_can('edit_post', $post_id)) {
|
||
return;
|
||
}
|
||
|
||
if (isset($_POST['ai_seo_title'])) {
|
||
update_post_meta($post_id, '_ai_seo_title', sanitize_text_field($_POST['ai_seo_title']));
|
||
}
|
||
|
||
if (isset($_POST['ai_seo_description'])) {
|
||
update_post_meta($post_id, '_ai_seo_description', sanitize_textarea_field($_POST['ai_seo_description']));
|
||
}
|
||
|
||
if (isset($_POST['ai_seo_keywords'])) {
|
||
update_post_meta($post_id, '_ai_seo_keywords', sanitize_text_field($_POST['ai_seo_keywords']));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 加载管理页面脚本和样式
|
||
*/
|
||
public function enqueue_admin_scripts($hook) {
|
||
if ('post.php' == $hook || 'post-new.php' == $hook || 'settings_page_ai-seo-generator' == $hook) {
|
||
wp_enqueue_script('ai-seo-admin', AI_SEO_PLUGIN_URL . 'assets/admin.js', array('jquery'), AI_SEO_VERSION, true);
|
||
wp_enqueue_style('ai-seo-admin', AI_SEO_PLUGIN_URL . 'assets/admin.css', array(), AI_SEO_VERSION);
|
||
|
||
wp_localize_script('ai-seo-admin', 'aiSeoAjax', array(
|
||
'ajax_url' => admin_url('admin-ajax.php'),
|
||
'nonce' => wp_create_nonce('ai_seo_nonce')
|
||
));
|
||
}
|
||
}
|
||
|
||
/**
|
||
* AJAX处理生成SEO内容
|
||
* 增强错误处理和调试信息
|
||
*/
|
||
public function ajax_generate_seo_content() {
|
||
// 增加PHP执行时间限制,防止长时间AI生成被中断
|
||
set_time_limit(180); // 设置为3分钟
|
||
|
||
check_ajax_referer('ai_seo_nonce', 'nonce');
|
||
|
||
$post_id = intval($_POST['post_id']);
|
||
$post = get_post($post_id);
|
||
|
||
if (!$post) {
|
||
wp_send_json_error('文章不存在');
|
||
return;
|
||
}
|
||
|
||
$content = $post->post_content;
|
||
$title = $post->post_title;
|
||
|
||
// 读取导航主题的自定义字段
|
||
$sites_link = get_post_meta($post_id, '_sites_link', true);
|
||
$sites_describe = get_post_meta($post_id, '_sites_sescribe', true);
|
||
|
||
// 构建完整的内容信息,包含自定义字段
|
||
$full_content = $content;
|
||
if (!empty($sites_link)) {
|
||
$full_content .= "\n\n网站链接: " . $sites_link;
|
||
}
|
||
if (!empty($sites_describe)) {
|
||
$full_content .= "\n\n网站描述: " . $sites_describe;
|
||
}
|
||
|
||
// 记录请求信息
|
||
error_log('AI SEO Request - Post ID: ' . $post_id . ', Title: ' . $title . ', Sites Link: ' . $sites_link . ', Sites Describe: ' . $sites_describe);
|
||
|
||
// 调用AI API生成SEO内容
|
||
$seo_data = $this->generate_seo_with_ai($title, $full_content);
|
||
|
||
if ($seo_data && is_array($seo_data)) {
|
||
// 记录成功信息
|
||
error_log('AI SEO Success: ' . json_encode($seo_data));
|
||
wp_send_json_success($seo_data);
|
||
} else {
|
||
// 记录失败信息
|
||
error_log('AI SEO Failed: seo_data = ' . var_export($seo_data, true));
|
||
wp_send_json_error('生成SEO内容失败,请查看错误日志获取详细信息');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 调用AI API生成SEO内容
|
||
* 增强调试和错误处理功能
|
||
*/
|
||
private function generate_seo_with_ai($title, $content) {
|
||
$api_key = get_option('ai_seo_api_key');
|
||
$api_url = get_option('ai_seo_api_url');
|
||
|
||
// 记录配置信息
|
||
error_log('AI SEO Config - API URL: ' . $api_url . ', API Key: ' . (empty($api_key) ? 'Empty' : 'Set'));
|
||
|
||
if (empty($api_key) || empty($api_url)) {
|
||
error_log('AI SEO Error: API Key or URL not configured');
|
||
return false;
|
||
}
|
||
|
||
// 检测是否包含导航网站信息
|
||
$is_navigation_site = (strpos($content, '网站链接:') !== false || strpos($content, '网站描述:') !== false);
|
||
|
||
if ($is_navigation_site) {
|
||
$prompt = "请根据以下导航网站信息,生成SEO优化的标题(Title)、描述(Description)和关键词(Keywords)。这是一个网站导航页面,请重点关注网站的功能、特色和用途:\n\n标题:{$title}\n\n内容:" . wp_strip_all_tags($content) . "\n\n请针对导航类网站的特点,生成吸引用户点击的SEO内容。以JSON格式返回,包含title、description、keywords字段。";
|
||
} else {
|
||
$prompt = "请根据以下文章标题和内容,生成SEO优化的标题(Title)、描述(Description)和关键词(Keywords):\n\n标题:{$title}\n\n内容:" . wp_strip_all_tags($content) . "\n\n请以JSON格式返回,包含title、description、keywords字段。";
|
||
}
|
||
|
||
$request_body = array(
|
||
'inputs' => array(),
|
||
'query' => $prompt,
|
||
'response_mode' => 'blocking',
|
||
'user' => 'wordpress-user'
|
||
);
|
||
|
||
// 记录请求信息
|
||
error_log('AI SEO Request Body: ' . json_encode($request_body));
|
||
|
||
$response = wp_remote_post($api_url . '/chat-messages', array(
|
||
'headers' => array(
|
||
'Authorization' => 'Bearer ' . $api_key,
|
||
'Content-Type' => 'application/json'
|
||
),
|
||
'body' => json_encode($request_body),
|
||
'timeout' => 120 // 增加超时时间到120秒(2分钟)
|
||
));
|
||
|
||
if (is_wp_error($response)) {
|
||
error_log('AI SEO WP Error: ' . $response->get_error_message());
|
||
return false;
|
||
}
|
||
|
||
$response_code = wp_remote_retrieve_response_code($response);
|
||
error_log('AI SEO Response Code: ' . $response_code);
|
||
|
||
$body = wp_remote_retrieve_body($response);
|
||
|
||
// 记录原始响应
|
||
error_log('AI SEO Raw Response: ' . $body);
|
||
|
||
if (empty($body)) {
|
||
error_log('AI SEO Error: Empty response body');
|
||
return false;
|
||
}
|
||
|
||
$data = json_decode($body, true);
|
||
$json_error = json_last_error();
|
||
|
||
if ($json_error !== JSON_ERROR_NONE) {
|
||
error_log('AI SEO JSON Error: ' . json_last_error_msg());
|
||
return false;
|
||
}
|
||
|
||
error_log('AI SEO Parsed Data: ' . json_encode($data));
|
||
|
||
// 方法1: 检查是否直接返回了SEO数据结构
|
||
if (isset($data['title'], $data['description'], $data['keywords'])) {
|
||
error_log('AI SEO: Found direct SEO data structure');
|
||
return array(
|
||
'title' => $data['title'],
|
||
'description' => $data['description'],
|
||
'keywords' => $data['keywords']
|
||
);
|
||
}
|
||
|
||
// 方法2: 检查answer字段中的JSON数据
|
||
if (isset($data['answer'])) {
|
||
$answer = $data['answer'];
|
||
error_log('AI SEO: Found answer field: ' . $answer);
|
||
|
||
// 尝试直接解析answer作为JSON
|
||
$seo_data = json_decode($answer, true);
|
||
if ($seo_data && isset($seo_data['title'], $seo_data['description'], $seo_data['keywords'])) {
|
||
error_log('AI SEO: Successfully parsed answer as JSON');
|
||
return $seo_data;
|
||
}
|
||
|
||
// 尝试从answer中提取JSON字符串
|
||
preg_match('/\{.*\}/s', $answer, $matches);
|
||
if (!empty($matches[0])) {
|
||
error_log('AI SEO: Extracted JSON from answer: ' . $matches[0]);
|
||
$seo_data = json_decode($matches[0], true);
|
||
if ($seo_data && isset($seo_data['title'], $seo_data['description'], $seo_data['keywords'])) {
|
||
error_log('AI SEO: Successfully parsed extracted JSON');
|
||
return $seo_data;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 方法3: 检查data字段中的内容
|
||
if (isset($data['data'])) {
|
||
$data_content = $data['data'];
|
||
error_log('AI SEO: Found data field: ' . json_encode($data_content));
|
||
if (is_array($data_content) && isset($data_content['title'], $data_content['description'], $data_content['keywords'])) {
|
||
error_log('AI SEO: Successfully found SEO data in data field');
|
||
return $data_content;
|
||
}
|
||
}
|
||
|
||
error_log('AI SEO: No valid SEO data found in response');
|
||
return false;
|
||
}
|
||
|
||
/**
|
||
* 自定义页面标题
|
||
*/
|
||
public function custom_wp_title($title, $sep) {
|
||
if (is_single() || is_page()) {
|
||
global $post;
|
||
$custom_title = get_post_meta($post->ID, '_ai_seo_title', true);
|
||
if (!empty($custom_title)) {
|
||
return $custom_title;
|
||
}
|
||
}
|
||
return $title;
|
||
}
|
||
|
||
/**
|
||
* 添加meta标签到页面头部
|
||
* 使用Open Graph标签避免与WordPress默认meta标签冲突
|
||
*/
|
||
public function add_meta_tags() {
|
||
if (is_single() || is_page()) {
|
||
global $post;
|
||
|
||
$seo_title = get_post_meta($post->ID, '_ai_seo_title', true);
|
||
$description = get_post_meta($post->ID, '_ai_seo_description', true);
|
||
$keywords = get_post_meta($post->ID, '_ai_seo_keywords', true);
|
||
|
||
// 输出Open Graph标题
|
||
if (!empty($seo_title)) {
|
||
echo '<meta property="og:title" content="' . esc_attr($seo_title) . '">' . "\n";
|
||
}
|
||
|
||
// 输出Open Graph描述
|
||
if (!empty($description)) {
|
||
echo '<meta property="og:description" content="' . esc_attr($description) . '">' . "\n";
|
||
}
|
||
|
||
// 保留keywords标签(Open Graph没有对应标签)
|
||
if (!empty($keywords)) {
|
||
echo '<meta name="keywords" content="' . esc_attr($keywords) . '">' . "\n";
|
||
}
|
||
|
||
// 添加其他常用的Open Graph标签
|
||
echo '<meta property="og:type" content="article">' . "\n";
|
||
echo '<meta property="og:url" content="' . esc_url(get_permalink($post->ID)) . '">' . "\n";
|
||
|
||
// 如果文章有特色图片,添加og:image
|
||
if (has_post_thumbnail($post->ID)) {
|
||
$thumbnail_url = get_the_post_thumbnail_url($post->ID, 'large');
|
||
echo '<meta property="og:image" content="' . esc_url($thumbnail_url) . '">' . "\n";
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// 初始化插件
|
||
new AiSeoGenerator();
|
||
?>
|