文章目录
-
- 在当今互联网环境中,用户生成内容(User-Generated Content, UGC)已成为网站互动性和价值的重要组成部分。从电商网站的产品评价、社交媒体平台的用户分享,到知识社区的问答讨论,UGC不仅丰富了网站内容,还增强了用户参与感和社区凝聚力。然而,UGC管理也带来了诸多挑战:垃圾信息泛滥、不当内容传播、版权问题以及内容质量参差不齐等。 对于WordPress网站管理员而言,构建一个高效、安全的UGC管理与审核系统至关重要。本教程将深入探讨如何通过WordPress代码二次开发,实现一个完整的用户生成内容管理与审核系统,同时集成常用互联网小工具功能,提升网站互动性和管理效率。
-
- 在开始开发前,我们需要明确网站需要管理的UGC类型: 评论系统:文章评论、产品评价 用户提交内容:文章投稿、图片上传、视频分享 社区互动:论坛帖子、问答内容 用户资料:个人简介、头像、联系方式
- 一个完整的UGC管理系统应包含以下核心功能: 内容提交接口:用户友好的内容提交表单 审核工作流:多级审核机制与状态管理 垃圾过滤:自动识别与过滤垃圾内容 用户信誉系统:基于用户行为的信任评分 通知系统:审核状态通知与用户提醒 管理后台:高效的内容审核与管理界面 数据分析:UGC数据统计与报告
- 我们将采用以下技术架构: 前端:HTML5、CSS3、JavaScript(jQuery/AJAX) 后端:PHP(WordPress核心API) 数据库:MySQL(WordPress数据库结构) 安全机制:Nonce验证、权限检查、数据过滤
-
- 首先,我们需要创建一个独立的WordPress插件来管理所有UGC功能: <?php /** * Plugin Name: UGC管理与审核系统 * Plugin URI: https://yourwebsite.com/ * Description: 用户生成内容管理与审核系统 * Version: 1.0.0 * Author: 您的名称 * License: GPL v2 or later */ // 防止直接访问 if (!defined('ABSPATH')) { exit; } // 定义插件常量 define('UGC_PLUGIN_PATH', plugin_dir_path(__FILE__)); define('UGC_PLUGIN_URL', plugin_dir_url(__FILE__)); define('UGC_VERSION', '1.0.0'); // 初始化插件 function ugc_system_init() { // 检查WordPress版本 if (version_compare(get_bloginfo('version'), '5.0', '<')) { wp_die('本插件需要WordPress 5.0或更高版本'); } // 加载核心功能 require_once UGC_PLUGIN_PATH . 'includes/core-functions.php'; require_once UGC_PLUGIN_PATH . 'includes/submission-handler.php'; require_once UGC_PLUGIN_PATH . 'includes/moderation-system.php'; require_once UGC_PLUGIN_PATH . 'includes/admin-interface.php'; // 国际化支持 load_plugin_textdomain('ugc-system', false, dirname(plugin_basename(__FILE__)) . '/languages'); } add_action('plugins_loaded', 'ugc_system_init');
- 我们需要扩展WordPress数据库来存储UGC相关数据: // 在activation hook中创建数据库表 function ugc_create_database_tables() { global $wpdb; $charset_collate = $wpdb->get_charset_collate(); $table_name = $wpdb->prefix . 'ugc_submissions'; $sql = "CREATE TABLE IF NOT EXISTS $table_name ( id bigint(20) NOT NULL AUTO_INCREMENT, user_id bigint(20) NOT NULL, content_type varchar(50) NOT NULL, title varchar(255), content longtext NOT NULL, status varchar(20) DEFAULT 'pending', moderation_notes text, moderated_by bigint(20), moderated_at datetime, created_at datetime DEFAULT CURRENT_TIMESTAMP, updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, metadata text, PRIMARY KEY (id), KEY user_id (user_id), KEY status (status), KEY content_type (content_type) ) $charset_collate;"; require_once(ABSPATH . 'wp-admin/includes/upgrade.php'); dbDelta($sql); // 创建审核日志表 $log_table = $wpdb->prefix . 'ugc_moderation_logs'; $sql_log = "CREATE TABLE IF NOT EXISTS $log_table ( id bigint(20) NOT NULL AUTO_INCREMENT, submission_id bigint(20) NOT NULL, moderator_id bigint(20) NOT NULL, action varchar(50) NOT NULL, notes text, created_at datetime DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), KEY submission_id (submission_id), KEY moderator_id (moderator_id) ) $charset_collate;"; dbDelta($sql_log); } register_activation_hook(__FILE__, 'ugc_create_database_tables');
-
- 设计一个用户友好的内容提交界面: // 短代码生成内容提交表单 function ugc_submission_form_shortcode($atts) { // 只有登录用户才能提交内容 if (!is_user_logged_in()) { return '<div class="ugc-login-required">请<a href="' . wp_login_url(get_permalink()) . '">登录</a>后提交内容</div>'; } $atts = shortcode_atts(array( 'type' => 'article', 'category' => '', 'max_length' => 5000 ), $atts); ob_start(); ?> <div class="ugc-submission-form-container"> <form id="ugc-submission-form" class="ugc-form" method="post" enctype="multipart/form-data"> <?php wp_nonce_field('ugc_submission_action', 'ugc_submission_nonce'); ?> <input type="hidden" name="ugc_content_type" value="<?php echo esc_attr($atts['type']); ?>"> <div class="form-group"> <label for="ugc-title">标题 *</label> <input type="text" id="ugc-title" name="ugc_title" required maxlength="200" placeholder="请输入内容标题"> </div> <div class="form-group"> <label for="ugc-content">内容 *</label> <textarea id="ugc-content" name="ugc_content" rows="10" required maxlength="<?php echo esc_attr($atts['max_length']); ?>" placeholder="请输入详细内容..."></textarea> <div class="char-count"> <span id="char-counter">0</span>/<?php echo esc_attr($atts['max_length']); ?> 字符 </div> </div> <div class="form-group"> <label for="ugc-category">分类</label> <select id="ugc-category" name="ugc_category"> <option value="">选择分类</option> <?php $categories = get_categories(array('hide_empty' => false)); foreach ($categories as $category) { echo '<option value="' . esc_attr($category->term_id) . '">' . esc_html($category->name) . '</option>'; } ?> </select> </div> <div class="form-group"> <label for="ugc-tags">标签</label> <input type="text" id="ugc-tags" name="ugc_tags" placeholder="用逗号分隔多个标签"> </div> <div class="form-group"> <label for="ugc-attachments">附件</label> <input type="file" id="ugc-attachments" name="ugc_attachments[]" multiple accept="image/*,.pdf,.doc,.docx"> <p class="help-text">支持图片、PDF、Word文档,单个文件不超过5MB</p> </div> <div class="form-group"> <label> <input type="checkbox" name="ugc_terms" required> 我同意<a href="<?php echo get_permalink(get_page_by_path('terms')); ?>" target="_blank">服务条款</a> </label> </div> <div class="form-submit"> <button type="submit" class="ugc-submit-btn">提交内容</button> <div class="form-feedback" id="form-feedback"></div> </div> </form> </div> <script> jQuery(document).ready(function($) { // 字符计数 $('#ugc-content').on('input', function() { var length = $(this).val().length; $('#char-counter').text(length); }); // AJAX表单提交 $('#ugc-submission-form').on('submit', function(e) { e.preventDefault(); var formData = new FormData(this); var submitBtn = $(this).find('.ugc-submit-btn'); submitBtn.prop('disabled', true).text('提交中...'); $('#form-feedback').removeClass('success error').html(''); $.ajax({ url: '<?php echo admin_url('admin-ajax.php'); ?>', type: 'POST', data: formData, processData: false, contentType: false, success: function(response) { if (response.success) { $('#form-feedback').addClass('success').html(response.data.message); $('#ugc-submission-form')[0].reset(); $('#char-counter').text('0'); } else { $('#form-feedback').addClass('error').html(response.data); } submitBtn.prop('disabled', false).text('提交内容'); }, error: function() { $('#form-feedback').addClass('error').html('提交失败,请稍后重试'); submitBtn.prop('disabled', false).text('提交内容'); } }); }); }); </script> <?php // 添加样式 wp_enqueue_style('ugc-frontend-style', UGC_PLUGIN_URL . 'assets/css/frontend.css'); wp_enqueue_script('ugc-frontend-script', UGC_PLUGIN_URL . 'assets/js/frontend.js', array('jquery'), UGC_VERSION, true); return ob_get_clean(); } add_shortcode('ugc_submission_form', 'ugc_submission_form_shortcode');
- // 处理AJAX内容提交 function handle_ugc_submission() { // 验证nonce if (!isset($_POST['ugc_submission_nonce']) || !wp_verify_nonce($_POST['ugc_submission_nonce'], 'ugc_submission_action')) { wp_die('安全验证失败'); } // 验证用户权限 if (!is_user_logged_in()) { wp_die('请先登录'); } $user_id = get_current_user_id(); $content_type = sanitize_text_field($_POST['ugc_content_type']); $title = sanitize_text_field($_POST['ugc_title']); $content = wp_kses_post($_POST['ugc_content']); $category = intval($_POST['ugc_category']); $tags = sanitize_text_field($_POST['ugc_tags']); // 基础验证 if (empty($title) || empty($content)) { wp_send_json_error('标题和内容不能为空'); } // 检查用户提交频率限制 if (!check_submission_rate_limit($user_id)) { wp_send_json_error('提交过于频繁,请稍后再试'); } // 垃圾内容检测 if (detect_spam_content($title . ' ' . $content)) { wp_send_json_error('内容疑似垃圾信息,请修改后重新提交'); } global $wpdb; $table_name = $wpdb->prefix . 'ugc_submissions'; // 准备元数据 $metadata = array( 'category_id' => $category, 'tags' => $tags, 'attachments' => array() ); // 处理文件上传 if (!empty($_FILES['ugc_attachments'])) { $attachments = handle_file_uploads($_FILES['ugc_attachments'], $user_id); if (is_wp_error($attachments)) { wp_send_json_error($attachments->get_error_message()); } $metadata['attachments'] = $attachments; } // 插入提交记录 $result = $wpdb->insert( $table_name, array( 'user_id' => $user_id, 'content_type' => $content_type, 'title' => $title, 'content' => $content, 'status' => 'pending', 'metadata' => serialize($metadata), 'created_at' => current_time('mysql') ), array('%d', '%s', '%s', '%s', '%s', '%s', '%s') ); if ($result) { $submission_id = $wpdb->insert_id; // 发送通知邮件给管理员 send_moderation_notification($submission_id); // 记录用户活动 update_user_submission_stats($user_id); wp_send_json_success(array( 'message' => '内容提交成功,等待审核', 'submission_id' => $submission_id )); } else { wp_send_json_error('提交失败,请稍后重试'); } } add_action('wp_ajax_ugc_submit_content', 'handle_ugc_submission'); add_action('wp_ajax_nopriv_ugc_submit_content', 'handle_ugc_submission'); // 文件上传处理函数 function handle_file_uploads($files, $user_id) { require_once(ABSPATH . 'wp-admin/includes/file.php'); require_once(ABSPATH . 'wp-admin/includes/image.php'); require_once(ABSPATH . 'wp-admin/includes/media.php'); $attachments = array(); $upload_dir = wp_upload_dir(); $ugc_dir = $upload_dir['basedir'] . '/ugc-uploads/' . $user_id . '/' . date('Y/m'); // 创建目录 if (!file_exists($ugc_dir)) { wp_mkdir_p($ugc_dir); } $file_count = count($files['name']); for ($i = 0; $i < $file_count; $i++) { // 检查文件大小(5MB限制) if ($files['size'][$i] > 5 * 1024 * 1024) { continue; // 跳过过大文件 } // 检查文件类型 $file_type = wp_check_filetype($files['name'][$i]); $allowed_types = array('jpg', 'jpeg', 'png', 'gif', 'pdf', 'doc', 'docx'); if (!in_array($file_type['ext'], $allowed_types)) { continue; // 跳过不允许的文件类型 } // 生成唯一文件名 $filename = wp_unique_filename($ugc_dir, $files['name'][$i]); $filepath = $ugc_dir . '/' . $filename; // 移动文件 if (move_uploaded_file($files['tmp_name'][$i], $filepath)) { $attachments[] = array( 'name' => $files['name'][$i], 'path' => str_replace($upload_dir['basedir'], '', $filepath), 'type' => $file_type['type'], 'size' => $files['size'][$i] ); } } return $attachments; }
-
- // 审核状态管理类 class UGC_Moderation_Workflow { private $statuses = array( 'pending' => array( 'name' => '待审核', 'actions' => array('approve', 'reject', 'request_revision') ), 'under_review' => array( 'name' => '审核中', 'actions' => array('approve', 'reject', 'request_revision') ), 'approved' => array( 'name' => '已通过', 'actions' => array('unpublish', 'delete') ), 'rejected' => array( 'name' => '已拒绝', 'actions' => array('restore', 'delete') ), 'needs_revision' => array( 'name' => '需要修改', 'actions' => array('approve', 'reject') ), 'published' => array( 'name' => '已发布', 'actions' => array('unpublish', 'delete') ) ); // 获取下一个可用状态 public function get_next_status($current_status, $action) { $transitions = array( 'pending' => array( 'approve' => 'approved', 'reject' => 'rejected', 'request_revision' => 'needs_revision' ), 'needs_revision' => array( 'approve' => 'approved', 'reject' => 'rejected' ), 'approved' => array( 'publish' => 'published', 'unpublish' => 'pending', 'delete' => 'deleted' ), 'rejected' => array( 'restore' => 'pending', 'delete' => 'deleted' ), 'published' => array( 'unpublish' => 'approved', 'delete' => 'deleted' ) ); return isset($transitions[$current_status][$action]) ? $transitions[$current_status][$action] : $current_status; } // 执行审核操作 public function moderate_submission($submission_id, $action, $moderator_id, $notes = '') { global $wpdb; $table_name = $wpdb->prefix . 'ugc_submissions'; $log_table = $wpdb->prefix . 'ugc_moderation_logs'; // 获取当前状态 $current_status = $wpdb->get_var($wpdb->prepare( "SELECT status FROM $table_name WHERE id = %d", $submission_id )); if (!$current_status) { return new WP_Error('not_found', '提交内容不存在'); } // 验证操作是否允许 if (!in_array($action, $this->statuses[$current_status]['actions'])) { return new WP_Error('invalid_action', '当前状态下不允许此操作'); } // 获取新状态 $new_status = $this->get_next_status($current_status, $action); // 开始事务 $wpdb->query('START TRANSACTION'); try { // 更新提交状态 $update_result = $wpdb->update( $table_name, array( 'status' => $new_status, 'moderated_by' => $moderator_id, 'moderated_at' => current_time('mysql'), 'moderation_notes' => $notes ), array('id' => $submission_id), array('%s', '%d', '%s', '%s'), array('%d') ); if (!$update_result) { throw new Exception('更新状态失败'); } // 记录审核日志 $log_result = $wpdb->insert( $log_table, array( 'submission_id' => $submission_id, 'moderator_id' => $moderator_id, 'action' => $action, 'notes' => $notes ), array('%d', '%d', '%s', '%s') ); if (!$log_result) { throw new Exception('记录日志失败'); } // 如果状态变为已发布,创建正式内容 if ($new_status === 'published') { $this->publish_submission($submission_id); } // 发送通知给用户 $this->send_status_notification($submission_id, $new_status, $notes); $wpdb->query('COMMIT'); return array( 'success' => true, 'new_status' => $new_status, 'message' => '审核操作成功' ); } catch (Exception $e) { $wpdb->query('ROLLBACK'); return new WP_Error('transaction_failed', $e->getMessage()); } } // 发布提交内容 private function publish_submission($submission_id) { global $wpdb; $table_name = $wpdb->prefix . 'ugc_submissions'; $submission = $wpdb->get_row($wpdb->prepare( "SELECT * FROM $table_name WHERE id = %d", $submission_id )); if (!$submission) { return false; } $metadata = unserialize($submission->metadata); // 创建WordPress文章 $post_data = array( 'post_title' => $submission->title, 'post_content' => $submission->content, 'post_status' => 'publish', 'post_author' => $submission->user_id, 'post_type' => 'post' ); if (!empty($metadata['category_id'])) { $post_data['post_category'] = array($metadata['category_id']); } $post_id = wp_insert_post($post_data); if ($post_id && !empty($metadata['tags'])) { wp_set_post_tags($post_id, $metadata['tags']); } // 更新提交记录中的文章ID $wpdb->update( $table_name, array('published_post_id' => $post_id), array('id' => $submission_id), array('%d'), array('%d') ); return $post_id; } // 发送状态通知 private function send_status_notification($submission_id, $status, $notes = '') { global $wpdb; $table_name = $wpdb->prefix . 'ugc_submissions'; $submission = $wpdb->get_row($wpdb->prepare( "SELECT user_id, title FROM $table_name WHERE id = %d", $submission_id )); if (!$submission) { return false; } $user = get_user_by('id', $submission->user_id); if (!$user) { return false; } $status_names = array( 'approved' => '已通过', 'rejected' => '已拒绝', 'published' => '已发布', 'needs_revision' => '需要修改' ); $subject = sprintf('您的投稿"%s"状态已更新', $submission->title); $message = sprintf( "您好 %s,nn您的投稿《%s》状态已更新为:%snn", $user->display_name, $submission->title, $status_names[$status] ?? $status ); if (!empty($notes)) { $message .= "审核备注:n" . $notes . "nn"; } $message .= "您可以登录网站查看详情。nn"; $message .= get_bloginfo('name'); wp_mail($user->user_email, $subject, $message); return true; } }
- // 垃圾内容检测系统 class UGC_Spam_Detection { private $spam_keywords = array(); private $spam_patterns = array(); public function __construct() { // 加载垃圾关键词库 $this->load_spam_keywords(); $this->load_spam_patterns(); } // 检测内容是否为垃圾 public function detect($content, $author_id = 0) { $score = 0; $reasons = array(); // 1. 关键词检测 $keyword_score = $this->check_keywords($content); if ($keyword_score > 0) { $score += $keyword_score; $reasons[] = '包含垃圾关键词'; } // 2. 链接检测 $link_score = $this->check_links($content); if ($link_score > 0) { $score += $link_score; $reasons[] = '包含可疑链接'; } // 3. 重复内容检测 $duplicate_score = $this->check_duplicate($content); if ($duplicate_score > 0) { $score += $duplicate_score; $reasons[] = '疑似重复内容'; } // 4. 用户行为分析 if ($author_id > 0) { $user_score = $this->check_user_behavior($author_id); if ($user_score > 0) { $score += $user_score; $reasons[] = '用户行为可疑'; } } // 5. 模式匹配 $pattern_score = $this->check_patterns($content); if ($pattern_score > 0) { $score += $pattern_score; $reasons[] = '匹配垃圾内容模式'; } return array( 'score' => $score, 'is_spam' => $score >= 5, // 阈值设为5分 'reasons' => $reasons, 'details' => array( 'keyword_score' => $keyword_score, 'link_score' => $link_score, 'duplicate_score' => $duplicate_score, 'user_score' => $user_score ?? 0, 'pattern_score' => $pattern_score ) ); } // 关键词检测 private function check_keywords($content) { $score = 0; $content_lower = strtolower($content); foreach ($this->spam_keywords as $keyword => $weight) { if (strpos($content_lower, $keyword) !== false) { $score += $weight; } } return min($score, 3); // 最高3分 } // 链接检测 private function check_links($content) { $score = 0; // 提取所有链接 preg_match_all('/https?://[^s]+/', $content, $matches); $links = $matches[0] ?? array(); if (count($links) > 3) { $score += 2; // 链接过多 } // 检查可疑域名 $suspicious_domains = array('.ru', '.cn', '.xyz', '.top', '.club'); foreach ($links as $link) { foreach ($suspicious_domains as $domain) { if (strpos($link, $domain) !== false) { $score += 1; break; } } } return min($score, 3); } // 重复内容检测 private function check_duplicate($content) { global $wpdb; // 计算内容哈希 $content_hash = md5(trim($content)); // 检查最近24小时内的重复内容 $table_name = $wpdb->prefix . 'ugc_submissions'; $one_day_ago = date('Y-m-d H:i:s', strtotime('-24 hours')); $count = $wpdb->get_var($wpdb->prepare( "SELECT COUNT(*) FROM $table_name WHERE MD5(content) = %s AND created_at > %s", $content_hash, $one_day_ago )); return $count > 0 ? 2 : 0; } // 用户行为分析 private function check_user_behavior($user_id) { global $wpdb; $score = 0; $table_name = $wpdb->prefix . 'ugc_submissions'; // 检查用户提交频率 $one_hour_ago = date('Y-m-d H:i:s', strtotime('-1 hour')); $recent_submissions = $wpdb->get_var($wpdb->prepare( "SELECT COUNT(*) FROM $table_name WHERE user_id = %d AND created_at > %s", $user_id, $one_hour_ago )); if ($recent_submissions > 5) { $score += 2; // 1小时内提交超过5次 } // 检查用户被拒绝率 $total_submissions = $wpdb->get_var($wpdb->prepare( "SELECT COUNT(*) FROM $table_name WHERE user_id = %d", $user_id )); if ($total_submissions > 0) { $rejected_count = $wpdb->get_var($wpdb->prepare( "SELECT COUNT(*) FROM $table_name WHERE user_id = %d AND status = 'rejected'", $user_id )); $rejection_rate = $rejected_count / $total_submissions; if ($rejection_rate > 0.5) { $score += 2; // 拒绝率超过50% } } return min($score, 3); } // 模式匹配检测 private function check_patterns($content) { $score = 0; foreach ($this->spam_patterns as $pattern => $weight) { if (preg_match($pattern, $content)) { $score += $weight; } } return min($score, 2); } // 加载垃圾关键词 private function load_spam_keywords() { // 可以从文件或数据库加载 $this->spam_keywords = array( 'viagra' => 2, 'casino' => 2, 'loan' => 1, 'mortgage' => 1, 'click here' => 1, 'buy now' => 1, 'discount' => 1, 'free' => 1, 'win' => 1, 'prize' => 1, // 添加更多关键词... ); } // 加载垃圾模式 private function load_spam_patterns() { $this->spam_patterns = array( '/[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,}/i' => 1, // 邮箱地址 '/bd{3}[-.]?d{3}[-.]?d{4}b/' => 1, // 电话号码 '/bd{4}[- ]?d{4}[- ]?d{4}[- ]?d{4}b/' => 2, // 信用卡号 '/http:///' => 1, // HTTP链接(非HTTPS) ); } }
在当今互联网环境中,用户生成内容(User-Generated Content, UGC)已成为网站互动性和价值的重要组成部分。从电商网站的产品评价、社交媒体平台的用户分享,到知识社区的问答讨论,UGC不仅丰富了网站内容,还增强了用户参与感和社区凝聚力。然而,UGC管理也带来了诸多挑战:垃圾信息泛滥、不当内容传播、版权问题以及内容质量参差不齐等。
对于WordPress网站管理员而言,构建一个高效、安全的UGC管理与审核系统至关重要。本教程将深入探讨如何通过WordPress代码二次开发,实现一个完整的用户生成内容管理与审核系统,同时集成常用互联网小工具功能,提升网站互动性和管理效率。
在开始开发前,我们需要明确网站需要管理的UGC类型:
- 评论系统:文章评论、产品评价
- 用户提交内容:文章投稿、图片上传、视频分享
- 社区互动:论坛帖子、问答内容
- 用户资料:个人简介、头像、联系方式
一个完整的UGC管理系统应包含以下核心功能:
- 内容提交接口:用户友好的内容提交表单
- 审核工作流:多级审核机制与状态管理
- 垃圾过滤:自动识别与过滤垃圾内容
- 用户信誉系统:基于用户行为的信任评分
- 通知系统:审核状态通知与用户提醒
- 管理后台:高效的内容审核与管理界面
- 数据分析:UGC数据统计与报告
我们将采用以下技术架构:
- 前端:HTML5、CSS3、JavaScript(jQuery/AJAX)
- 后端:PHP(WordPress核心API)
- 数据库:MySQL(WordPress数据库结构)
- 安全机制:Nonce验证、权限检查、数据过滤
首先,我们需要创建一个独立的WordPress插件来管理所有UGC功能:
<?php
/**
* Plugin Name: UGC管理与审核系统
* Plugin URI: https://yourwebsite.com/
* Description: 用户生成内容管理与审核系统
* Version: 1.0.0
* Author: 您的名称
* License: GPL v2 or later
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('UGC_PLUGIN_PATH', plugin_dir_path(__FILE__));
define('UGC_PLUGIN_URL', plugin_dir_url(__FILE__));
define('UGC_VERSION', '1.0.0');
// 初始化插件
function ugc_system_init() {
// 检查WordPress版本
if (version_compare(get_bloginfo('version'), '5.0', '<')) {
wp_die('本插件需要WordPress 5.0或更高版本');
}
// 加载核心功能
require_once UGC_PLUGIN_PATH . 'includes/core-functions.php';
require_once UGC_PLUGIN_PATH . 'includes/submission-handler.php';
require_once UGC_PLUGIN_PATH . 'includes/moderation-system.php';
require_once UGC_PLUGIN_PATH . 'includes/admin-interface.php';
// 国际化支持
load_plugin_textdomain('ugc-system', false, dirname(plugin_basename(__FILE__)) . '/languages');
}
add_action('plugins_loaded', 'ugc_system_init');
我们需要扩展WordPress数据库来存储UGC相关数据:
// 在activation hook中创建数据库表
function ugc_create_database_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$table_name = $wpdb->prefix . 'ugc_submissions';
$sql = "CREATE TABLE IF NOT EXISTS $table_name (
id bigint(20) NOT NULL AUTO_INCREMENT,
user_id bigint(20) NOT NULL,
content_type varchar(50) NOT NULL,
title varchar(255),
content longtext NOT NULL,
status varchar(20) DEFAULT 'pending',
moderation_notes text,
moderated_by bigint(20),
moderated_at datetime,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
updated_at datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
metadata text,
PRIMARY KEY (id),
KEY user_id (user_id),
KEY status (status),
KEY content_type (content_type)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
// 创建审核日志表
$log_table = $wpdb->prefix . 'ugc_moderation_logs';
$sql_log = "CREATE TABLE IF NOT EXISTS $log_table (
id bigint(20) NOT NULL AUTO_INCREMENT,
submission_id bigint(20) NOT NULL,
moderator_id bigint(20) NOT NULL,
action varchar(50) NOT NULL,
notes text,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY submission_id (submission_id),
KEY moderator_id (moderator_id)
) $charset_collate;";
dbDelta($sql_log);
}
register_activation_hook(__FILE__, 'ugc_create_database_tables');
设计一个用户友好的内容提交界面:
// 短代码生成内容提交表单
function ugc_submission_form_shortcode($atts) {
// 只有登录用户才能提交内容
if (!is_user_logged_in()) {
return '<div class="ugc-login-required">请<a href="' . wp_login_url(get_permalink()) . '">登录</a>后提交内容</div>';
}
$atts = shortcode_atts(array(
'type' => 'article',
'category' => '',
'max_length' => 5000
), $atts);
ob_start();
?>
<div class="ugc-submission-form-container">
<form id="ugc-submission-form" class="ugc-form" method="post" enctype="multipart/form-data">
<?php wp_nonce_field('ugc_submission_action', 'ugc_submission_nonce'); ?>
<input type="hidden" name="ugc_content_type" value="<?php echo esc_attr($atts['type']); ?>">
<div class="form-group">
<label for="ugc-title">标题 *</label>
<input type="text" id="ugc-title" name="ugc_title" required
maxlength="200" placeholder="请输入内容标题">
</div>
<div class="form-group">
<label for="ugc-content">内容 *</label>
<textarea id="ugc-content" name="ugc_content" rows="10"
required maxlength="<?php echo esc_attr($atts['max_length']); ?>"
placeholder="请输入详细内容..."></textarea>
<div class="char-count">
<span id="char-counter">0</span>/<?php echo esc_attr($atts['max_length']); ?> 字符
</div>
</div>
<div class="form-group">
<label for="ugc-category">分类</label>
<select id="ugc-category" name="ugc_category">
<option value="">选择分类</option>
<?php
$categories = get_categories(array('hide_empty' => false));
foreach ($categories as $category) {
echo '<option value="' . esc_attr($category->term_id) . '">' .
esc_html($category->name) . '</option>';
}
?>
</select>
</div>
<div class="form-group">
<label for="ugc-tags">标签</label>
<input type="text" id="ugc-tags" name="ugc_tags"
placeholder="用逗号分隔多个标签">
</div>
<div class="form-group">
<label for="ugc-attachments">附件</label>
<input type="file" id="ugc-attachments" name="ugc_attachments[]"
multiple accept="image/*,.pdf,.doc,.docx">
<p class="help-text">支持图片、PDF、Word文档,单个文件不超过5MB</p>
</div>
<div class="form-group">
<label>
<input type="checkbox" name="ugc_terms" required>
我同意<a href="<?php echo get_permalink(get_page_by_path('terms')); ?>" target="_blank">服务条款</a>
</label>
</div>
<div class="form-submit">
<button type="submit" class="ugc-submit-btn">提交内容</button>
<div class="form-feedback" id="form-feedback"></div>
</div>
</form>
</div>
<script>
jQuery(document).ready(function($) {
// 字符计数
$('#ugc-content').on('input', function() {
var length = $(this).val().length;
$('#char-counter').text(length);
});
// AJAX表单提交
$('#ugc-submission-form').on('submit', function(e) {
e.preventDefault();
var formData = new FormData(this);
var submitBtn = $(this).find('.ugc-submit-btn');
submitBtn.prop('disabled', true).text('提交中...');
$('#form-feedback').removeClass('success error').html('');
$.ajax({
url: '<?php echo admin_url('admin-ajax.php'); ?>',
type: 'POST',
data: formData,
processData: false,
contentType: false,
success: function(response) {
if (response.success) {
$('#form-feedback').addClass('success').html(response.data.message);
$('#ugc-submission-form')[0].reset();
$('#char-counter').text('0');
} else {
$('#form-feedback').addClass('error').html(response.data);
}
submitBtn.prop('disabled', false).text('提交内容');
},
error: function() {
$('#form-feedback').addClass('error').html('提交失败,请稍后重试');
submitBtn.prop('disabled', false).text('提交内容');
}
});
});
});
</script>
<?php
// 添加样式
wp_enqueue_style('ugc-frontend-style', UGC_PLUGIN_URL . 'assets/css/frontend.css');
wp_enqueue_script('ugc-frontend-script', UGC_PLUGIN_URL . 'assets/js/frontend.js',
array('jquery'), UGC_VERSION, true);
return ob_get_clean();
}
add_shortcode('ugc_submission_form', 'ugc_submission_form_shortcode');
// 处理AJAX内容提交
function handle_ugc_submission() {
// 验证nonce
if (!isset($_POST['ugc_submission_nonce']) ||
!wp_verify_nonce($_POST['ugc_submission_nonce'], 'ugc_submission_action')) {
wp_die('安全验证失败');
}
// 验证用户权限
if (!is_user_logged_in()) {
wp_die('请先登录');
}
$user_id = get_current_user_id();
$content_type = sanitize_text_field($_POST['ugc_content_type']);
$title = sanitize_text_field($_POST['ugc_title']);
$content = wp_kses_post($_POST['ugc_content']);
$category = intval($_POST['ugc_category']);
$tags = sanitize_text_field($_POST['ugc_tags']);
// 基础验证
if (empty($title) || empty($content)) {
wp_send_json_error('标题和内容不能为空');
}
// 检查用户提交频率限制
if (!check_submission_rate_limit($user_id)) {
wp_send_json_error('提交过于频繁,请稍后再试');
}
// 垃圾内容检测
if (detect_spam_content($title . ' ' . $content)) {
wp_send_json_error('内容疑似垃圾信息,请修改后重新提交');
}
global $wpdb;
$table_name = $wpdb->prefix . 'ugc_submissions';
// 准备元数据
$metadata = array(
'category_id' => $category,
'tags' => $tags,
'attachments' => array()
);
// 处理文件上传
if (!empty($_FILES['ugc_attachments'])) {
$attachments = handle_file_uploads($_FILES['ugc_attachments'], $user_id);
if (is_wp_error($attachments)) {
wp_send_json_error($attachments->get_error_message());
}
$metadata['attachments'] = $attachments;
}
// 插入提交记录
$result = $wpdb->insert(
$table_name,
array(
'user_id' => $user_id,
'content_type' => $content_type,
'title' => $title,
'content' => $content,
'status' => 'pending',
'metadata' => serialize($metadata),
'created_at' => current_time('mysql')
),
array('%d', '%s', '%s', '%s', '%s', '%s', '%s')
);
if ($result) {
$submission_id = $wpdb->insert_id;
// 发送通知邮件给管理员
send_moderation_notification($submission_id);
// 记录用户活动
update_user_submission_stats($user_id);
wp_send_json_success(array(
'message' => '内容提交成功,等待审核',
'submission_id' => $submission_id
));
} else {
wp_send_json_error('提交失败,请稍后重试');
}
}
add_action('wp_ajax_ugc_submit_content', 'handle_ugc_submission');
add_action('wp_ajax_nopriv_ugc_submit_content', 'handle_ugc_submission');
// 文件上传处理函数
function handle_file_uploads($files, $user_id) {
require_once(ABSPATH . 'wp-admin/includes/file.php');
require_once(ABSPATH . 'wp-admin/includes/image.php');
require_once(ABSPATH . 'wp-admin/includes/media.php');
$attachments = array();
$upload_dir = wp_upload_dir();
$ugc_dir = $upload_dir['basedir'] . '/ugc-uploads/' . $user_id . '/' . date('Y/m');
// 创建目录
if (!file_exists($ugc_dir)) {
wp_mkdir_p($ugc_dir);
}
$file_count = count($files['name']);
for ($i = 0; $i < $file_count; $i++) {
// 检查文件大小(5MB限制)
if ($files['size'][$i] > 5 * 1024 * 1024) {
continue; // 跳过过大文件
}
// 检查文件类型
$file_type = wp_check_filetype($files['name'][$i]);
$allowed_types = array('jpg', 'jpeg', 'png', 'gif', 'pdf', 'doc', 'docx');
if (!in_array($file_type['ext'], $allowed_types)) {
continue; // 跳过不允许的文件类型
}
// 生成唯一文件名
$filename = wp_unique_filename($ugc_dir, $files['name'][$i]);
$filepath = $ugc_dir . '/' . $filename;
// 移动文件
if (move_uploaded_file($files['tmp_name'][$i], $filepath)) {
$attachments[] = array(
'name' => $files['name'][$i],
'path' => str_replace($upload_dir['basedir'], '', $filepath),
'type' => $file_type['type'],
'size' => $files['size'][$i]
);
}
}
return $attachments;
}
// 处理AJAX内容提交
function handle_ugc_submission() {
// 验证nonce
if (!isset($_POST['ugc_submission_nonce']) ||
!wp_verify_nonce($_POST['ugc_submission_nonce'], 'ugc_submission_action')) {
wp_die('安全验证失败');
}
// 验证用户权限
if (!is_user_logged_in()) {
wp_die('请先登录');
}
$user_id = get_current_user_id();
$content_type = sanitize_text_field($_POST['ugc_content_type']);
$title = sanitize_text_field($_POST['ugc_title']);
$content = wp_kses_post($_POST['ugc_content']);
$category = intval($_POST['ugc_category']);
$tags = sanitize_text_field($_POST['ugc_tags']);
// 基础验证
if (empty($title) || empty($content)) {
wp_send_json_error('标题和内容不能为空');
}
// 检查用户提交频率限制
if (!check_submission_rate_limit($user_id)) {
wp_send_json_error('提交过于频繁,请稍后再试');
}
// 垃圾内容检测
if (detect_spam_content($title . ' ' . $content)) {
wp_send_json_error('内容疑似垃圾信息,请修改后重新提交');
}
global $wpdb;
$table_name = $wpdb->prefix . 'ugc_submissions';
// 准备元数据
$metadata = array(
'category_id' => $category,
'tags' => $tags,
'attachments' => array()
);
// 处理文件上传
if (!empty($_FILES['ugc_attachments'])) {
$attachments = handle_file_uploads($_FILES['ugc_attachments'], $user_id);
if (is_wp_error($attachments)) {
wp_send_json_error($attachments->get_error_message());
}
$metadata['attachments'] = $attachments;
}
// 插入提交记录
$result = $wpdb->insert(
$table_name,
array(
'user_id' => $user_id,
'content_type' => $content_type,
'title' => $title,
'content' => $content,
'status' => 'pending',
'metadata' => serialize($metadata),
'created_at' => current_time('mysql')
),
array('%d', '%s', '%s', '%s', '%s', '%s', '%s')
);
if ($result) {
$submission_id = $wpdb->insert_id;
// 发送通知邮件给管理员
send_moderation_notification($submission_id);
// 记录用户活动
update_user_submission_stats($user_id);
wp_send_json_success(array(
'message' => '内容提交成功,等待审核',
'submission_id' => $submission_id
));
} else {
wp_send_json_error('提交失败,请稍后重试');
}
}
add_action('wp_ajax_ugc_submit_content', 'handle_ugc_submission');
add_action('wp_ajax_nopriv_ugc_submit_content', 'handle_ugc_submission');
// 文件上传处理函数
function handle_file_uploads($files, $user_id) {
require_once(ABSPATH . 'wp-admin/includes/file.php');
require_once(ABSPATH . 'wp-admin/includes/image.php');
require_once(ABSPATH . 'wp-admin/includes/media.php');
$attachments = array();
$upload_dir = wp_upload_dir();
$ugc_dir = $upload_dir['basedir'] . '/ugc-uploads/' . $user_id . '/' . date('Y/m');
// 创建目录
if (!file_exists($ugc_dir)) {
wp_mkdir_p($ugc_dir);
}
$file_count = count($files['name']);
for ($i = 0; $i < $file_count; $i++) {
// 检查文件大小(5MB限制)
if ($files['size'][$i] > 5 * 1024 * 1024) {
continue; // 跳过过大文件
}
// 检查文件类型
$file_type = wp_check_filetype($files['name'][$i]);
$allowed_types = array('jpg', 'jpeg', 'png', 'gif', 'pdf', 'doc', 'docx');
if (!in_array($file_type['ext'], $allowed_types)) {
continue; // 跳过不允许的文件类型
}
// 生成唯一文件名
$filename = wp_unique_filename($ugc_dir, $files['name'][$i]);
$filepath = $ugc_dir . '/' . $filename;
// 移动文件
if (move_uploaded_file($files['tmp_name'][$i], $filepath)) {
$attachments[] = array(
'name' => $files['name'][$i],
'path' => str_replace($upload_dir['basedir'], '', $filepath),
'type' => $file_type['type'],
'size' => $files['size'][$i]
);
}
}
return $attachments;
}
// 审核状态管理类
class UGC_Moderation_Workflow {
private $statuses = array(
'pending' => array(
'name' => '待审核',
'actions' => array('approve', 'reject', 'request_revision')
),
'under_review' => array(
'name' => '审核中',
'actions' => array('approve', 'reject', 'request_revision')
),
'approved' => array(
'name' => '已通过',
'actions' => array('unpublish', 'delete')
),
'rejected' => array(
'name' => '已拒绝',
'actions' => array('restore', 'delete')
),
'needs_revision' => array(
'name' => '需要修改',
'actions' => array('approve', 'reject')
),
'published' => array(
'name' => '已发布',
'actions' => array('unpublish', 'delete')
)
);
// 获取下一个可用状态
public function get_next_status($current_status, $action) {
$transitions = array(
'pending' => array(
'approve' => 'approved',
'reject' => 'rejected',
'request_revision' => 'needs_revision'
),
'needs_revision' => array(
'approve' => 'approved',
'reject' => 'rejected'
),
'approved' => array(
'publish' => 'published',
'unpublish' => 'pending',
'delete' => 'deleted'
),
'rejected' => array(
'restore' => 'pending',
'delete' => 'deleted'
),
'published' => array(
'unpublish' => 'approved',
'delete' => 'deleted'
)
);
return isset($transitions[$current_status][$action])
? $transitions[$current_status][$action]
: $current_status;
}
// 执行审核操作
public function moderate_submission($submission_id, $action, $moderator_id, $notes = '') {
global $wpdb;
$table_name = $wpdb->prefix . 'ugc_submissions';
$log_table = $wpdb->prefix . 'ugc_moderation_logs';
// 获取当前状态
$current_status = $wpdb->get_var($wpdb->prepare(
"SELECT status FROM $table_name WHERE id = %d", $submission_id
));
if (!$current_status) {
return new WP_Error('not_found', '提交内容不存在');
}
// 验证操作是否允许
if (!in_array($action, $this->statuses[$current_status]['actions'])) {
return new WP_Error('invalid_action', '当前状态下不允许此操作');
}
// 获取新状态
$new_status = $this->get_next_status($current_status, $action);
// 开始事务
$wpdb->query('START TRANSACTION');
try {
// 更新提交状态
$update_result = $wpdb->update(
$table_name,
array(
'status' => $new_status,
'moderated_by' => $moderator_id,
'moderated_at' => current_time('mysql'),
'moderation_notes' => $notes
),
array('id' => $submission_id),
array('%s', '%d', '%s', '%s'),
array('%d')
);
if (!$update_result) {
throw new Exception('更新状态失败');
}
// 记录审核日志
$log_result = $wpdb->insert(
$log_table,
array(
'submission_id' => $submission_id,
'moderator_id' => $moderator_id,
'action' => $action,
'notes' => $notes
),
array('%d', '%d', '%s', '%s')
);
if (!$log_result) {
throw new Exception('记录日志失败');
}
// 如果状态变为已发布,创建正式内容
if ($new_status === 'published') {
$this->publish_submission($submission_id);
}
// 发送通知给用户
$this->send_status_notification($submission_id, $new_status, $notes);
$wpdb->query('COMMIT');
return array(
'success' => true,
'new_status' => $new_status,
'message' => '审核操作成功'
);
} catch (Exception $e) {
$wpdb->query('ROLLBACK');
return new WP_Error('transaction_failed', $e->getMessage());
}
}
// 发布提交内容
private function publish_submission($submission_id) {
global $wpdb;
$table_name = $wpdb->prefix . 'ugc_submissions';
$submission = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM $table_name WHERE id = %d", $submission_id
));
if (!$submission) {
return false;
}
$metadata = unserialize($submission->metadata);
// 创建WordPress文章
$post_data = array(
'post_title' => $submission->title,
'post_content' => $submission->content,
'post_status' => 'publish',
'post_author' => $submission->user_id,
'post_type' => 'post'
);
if (!empty($metadata['category_id'])) {
$post_data['post_category'] = array($metadata['category_id']);
}
$post_id = wp_insert_post($post_data);
if ($post_id && !empty($metadata['tags'])) {
wp_set_post_tags($post_id, $metadata['tags']);
}
// 更新提交记录中的文章ID
$wpdb->update(
$table_name,
array('published_post_id' => $post_id),
array('id' => $submission_id),
array('%d'),
array('%d')
);
return $post_id;
}
// 发送状态通知
private function send_status_notification($submission_id, $status, $notes = '') {
global $wpdb;
$table_name = $wpdb->prefix . 'ugc_submissions';
$submission = $wpdb->get_row($wpdb->prepare(
"SELECT user_id, title FROM $table_name WHERE id = %d", $submission_id
));
if (!$submission) {
return false;
}
$user = get_user_by('id', $submission->user_id);
if (!$user) {
return false;
}
$status_names = array(
'approved' => '已通过',
'rejected' => '已拒绝',
'published' => '已发布',
'needs_revision' => '需要修改'
);
$subject = sprintf('您的投稿"%s"状态已更新', $submission->title);
$message = sprintf(
"您好 %s,nn您的投稿《%s》状态已更新为:%snn",
$user->display_name,
$submission->title,
$status_names[$status] ?? $status
);
if (!empty($notes)) {
$message .= "审核备注:n" . $notes . "nn";
}
$message .= "您可以登录网站查看详情。nn";
$message .= get_bloginfo('name');
wp_mail($user->user_email, $subject, $message);
return true;
}
}
// 审核状态管理类
class UGC_Moderation_Workflow {
private $statuses = array(
'pending' => array(
'name' => '待审核',
'actions' => array('approve', 'reject', 'request_revision')
),
'under_review' => array(
'name' => '审核中',
'actions' => array('approve', 'reject', 'request_revision')
),
'approved' => array(
'name' => '已通过',
'actions' => array('unpublish', 'delete')
),
'rejected' => array(
'name' => '已拒绝',
'actions' => array('restore', 'delete')
),
'needs_revision' => array(
'name' => '需要修改',
'actions' => array('approve', 'reject')
),
'published' => array(
'name' => '已发布',
'actions' => array('unpublish', 'delete')
)
);
// 获取下一个可用状态
public function get_next_status($current_status, $action) {
$transitions = array(
'pending' => array(
'approve' => 'approved',
'reject' => 'rejected',
'request_revision' => 'needs_revision'
),
'needs_revision' => array(
'approve' => 'approved',
'reject' => 'rejected'
),
'approved' => array(
'publish' => 'published',
'unpublish' => 'pending',
'delete' => 'deleted'
),
'rejected' => array(
'restore' => 'pending',
'delete' => 'deleted'
),
'published' => array(
'unpublish' => 'approved',
'delete' => 'deleted'
)
);
return isset($transitions[$current_status][$action])
? $transitions[$current_status][$action]
: $current_status;
}
// 执行审核操作
public function moderate_submission($submission_id, $action, $moderator_id, $notes = '') {
global $wpdb;
$table_name = $wpdb->prefix . 'ugc_submissions';
$log_table = $wpdb->prefix . 'ugc_moderation_logs';
// 获取当前状态
$current_status = $wpdb->get_var($wpdb->prepare(
"SELECT status FROM $table_name WHERE id = %d", $submission_id
));
if (!$current_status) {
return new WP_Error('not_found', '提交内容不存在');
}
// 验证操作是否允许
if (!in_array($action, $this->statuses[$current_status]['actions'])) {
return new WP_Error('invalid_action', '当前状态下不允许此操作');
}
// 获取新状态
$new_status = $this->get_next_status($current_status, $action);
// 开始事务
$wpdb->query('START TRANSACTION');
try {
// 更新提交状态
$update_result = $wpdb->update(
$table_name,
array(
'status' => $new_status,
'moderated_by' => $moderator_id,
'moderated_at' => current_time('mysql'),
'moderation_notes' => $notes
),
array('id' => $submission_id),
array('%s', '%d', '%s', '%s'),
array('%d')
);
if (!$update_result) {
throw new Exception('更新状态失败');
}
// 记录审核日志
$log_result = $wpdb->insert(
$log_table,
array(
'submission_id' => $submission_id,
'moderator_id' => $moderator_id,
'action' => $action,
'notes' => $notes
),
array('%d', '%d', '%s', '%s')
);
if (!$log_result) {
throw new Exception('记录日志失败');
}
// 如果状态变为已发布,创建正式内容
if ($new_status === 'published') {
$this->publish_submission($submission_id);
}
// 发送通知给用户
$this->send_status_notification($submission_id, $new_status, $notes);
$wpdb->query('COMMIT');
return array(
'success' => true,
'new_status' => $new_status,
'message' => '审核操作成功'
);
} catch (Exception $e) {
$wpdb->query('ROLLBACK');
return new WP_Error('transaction_failed', $e->getMessage());
}
}
// 发布提交内容
private function publish_submission($submission_id) {
global $wpdb;
$table_name = $wpdb->prefix . 'ugc_submissions';
$submission = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM $table_name WHERE id = %d", $submission_id
));
if (!$submission) {
return false;
}
$metadata = unserialize($submission->metadata);
// 创建WordPress文章
$post_data = array(
'post_title' => $submission->title,
'post_content' => $submission->content,
'post_status' => 'publish',
'post_author' => $submission->user_id,
'post_type' => 'post'
);
if (!empty($metadata['category_id'])) {
$post_data['post_category'] = array($metadata['category_id']);
}
$post_id = wp_insert_post($post_data);
if ($post_id && !empty($metadata['tags'])) {
wp_set_post_tags($post_id, $metadata['tags']);
}
// 更新提交记录中的文章ID
$wpdb->update(
$table_name,
array('published_post_id' => $post_id),
array('id' => $submission_id),
array('%d'),
array('%d')
);
return $post_id;
}
// 发送状态通知
private function send_status_notification($submission_id, $status, $notes = '') {
global $wpdb;
$table_name = $wpdb->prefix . 'ugc_submissions';
$submission = $wpdb->get_row($wpdb->prepare(
"SELECT user_id, title FROM $table_name WHERE id = %d", $submission_id
));
if (!$submission) {
return false;
}
$user = get_user_by('id', $submission->user_id);
if (!$user) {
return false;
}
$status_names = array(
'approved' => '已通过',
'rejected' => '已拒绝',
'published' => '已发布',
'needs_revision' => '需要修改'
);
$subject = sprintf('您的投稿"%s"状态已更新', $submission->title);
$message = sprintf(
"您好 %s,nn您的投稿《%s》状态已更新为:%snn",
$user->display_name,
$submission->title,
$status_names[$status] ?? $status
);
if (!empty($notes)) {
$message .= "审核备注:n" . $notes . "nn";
}
$message .= "您可以登录网站查看详情。nn";
$message .= get_bloginfo('name');
wp_mail($user->user_email, $subject, $message);
return true;
}
}
// 垃圾内容检测系统
class UGC_Spam_Detection {
private $spam_keywords = array();
private $spam_patterns = array();
public function __construct() {
// 加载垃圾关键词库
$this->load_spam_keywords();
$this->load_spam_patterns();
}
// 检测内容是否为垃圾
public function detect($content, $author_id = 0) {
$score = 0;
$reasons = array();
// 1. 关键词检测
$keyword_score = $this->check_keywords($content);
if ($keyword_score > 0) {
$score += $keyword_score;
$reasons[] = '包含垃圾关键词';
}
// 2. 链接检测
$link_score = $this->check_links($content);
if ($link_score > 0) {
$score += $link_score;
$reasons[] = '包含可疑链接';
}
// 3. 重复内容检测
$duplicate_score = $this->check_duplicate($content);
if ($duplicate_score > 0) {
$score += $duplicate_score;
$reasons[] = '疑似重复内容';
}
// 4. 用户行为分析
if ($author_id > 0) {
$user_score = $this->check_user_behavior($author_id);
if ($user_score > 0) {
$score += $user_score;
$reasons[] = '用户行为可疑';
}
}
// 5. 模式匹配
$pattern_score = $this->check_patterns($content);
if ($pattern_score > 0) {
$score += $pattern_score;
$reasons[] = '匹配垃圾内容模式';
}
return array(
'score' => $score,
'is_spam' => $score >= 5, // 阈值设为5分
'reasons' => $reasons,
'details' => array(
'keyword_score' => $keyword_score,
'link_score' => $link_score,
'duplicate_score' => $duplicate_score,
'user_score' => $user_score ?? 0,
'pattern_score' => $pattern_score
)
);
}
// 关键词检测
private function check_keywords($content) {
$score = 0;
$content_lower = strtolower($content);
foreach ($this->spam_keywords as $keyword => $weight) {
if (strpos($content_lower, $keyword) !== false) {
$score += $weight;
}
}
return min($score, 3); // 最高3分
}
// 链接检测
private function check_links($content) {
$score = 0;
// 提取所有链接
preg_match_all('/https?://[^s]+/', $content, $matches);
$links = $matches[0] ?? array();
if (count($links) > 3) {
$score += 2; // 链接过多
}
// 检查可疑域名
$suspicious_domains = array('.ru', '.cn', '.xyz', '.top', '.club');
foreach ($links as $link) {
foreach ($suspicious_domains as $domain) {
if (strpos($link, $domain) !== false) {
$score += 1;
break;
}
}
}
return min($score, 3);
}
// 重复内容检测
private function check_duplicate($content) {
global $wpdb;
// 计算内容哈希
$content_hash = md5(trim($content));
// 检查最近24小时内的重复内容
$table_name = $wpdb->prefix . 'ugc_submissions';
$one_day_ago = date('Y-m-d H:i:s', strtotime('-24 hours'));
$count = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $table_name
WHERE MD5(content) = %s
AND created_at > %s",
$content_hash,
$one_day_ago
));
return $count > 0 ? 2 : 0;
}
// 用户行为分析
private function check_user_behavior($user_id) {
global $wpdb;
$score = 0;
$table_name = $wpdb->prefix . 'ugc_submissions';
// 检查用户提交频率
$one_hour_ago = date('Y-m-d H:i:s', strtotime('-1 hour'));
$recent_submissions = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $table_name
WHERE user_id = %d
AND created_at > %s",
$user_id,
$one_hour_ago
));
if ($recent_submissions > 5) {
$score += 2; // 1小时内提交超过5次
}
// 检查用户被拒绝率
$total_submissions = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $table_name WHERE user_id = %d",
$user_id
));
if ($total_submissions > 0) {
$rejected_count = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $table_name
WHERE user_id = %d AND status = 'rejected'",
$user_id
));
$rejection_rate = $rejected_count / $total_submissions;
if ($rejection_rate > 0.5) {
$score += 2; // 拒绝率超过50%
}
}
return min($score, 3);
}
// 模式匹配检测
private function check_patterns($content) {
$score = 0;
foreach ($this->spam_patterns as $pattern => $weight) {
if (preg_match($pattern, $content)) {
$score += $weight;
}
}
return min($score, 2);
}
// 加载垃圾关键词
private function load_spam_keywords() {
// 可以从文件或数据库加载
$this->spam_keywords = array(
'viagra' => 2,
'casino' => 2,
'loan' => 1,
'mortgage' => 1,
'click here' => 1,
'buy now' => 1,
'discount' => 1,
'free' => 1,
'win' => 1,
'prize' => 1,
// 添加更多关键词...
);
}
// 加载垃圾模式
private function load_spam_patterns() {
$this->spam_patterns = array(
'/[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,}/i' => 1, // 邮箱地址
'/bd{3}[-.]?d{3}[-.]?d{4}b/' => 1, // 电话号码
'/bd{4}[- ]?d{4}[- ]?d{4}[- ]?d{4}b/' => 2, // 信用卡号
'/http:///' => 1, // HTTP链接(非HTTPS)
);
}
}
// 垃圾内容检测系统
class UGC_Spam_Detection {
private $spam_keywords = array();
private $spam_patterns = array();
public function __construct() {
// 加载垃圾关键词库
$this->load_spam_keywords();
$this->load_spam_patterns();
}
// 检测内容是否为垃圾
public function detect($content, $author_id = 0) {
$score = 0;
$reasons = array();
// 1. 关键词检测
$keyword_score = $this->check_keywords($content);
if ($keyword_score > 0) {
$score += $keyword_score;
$reasons[] = '包含垃圾关键词';
}
// 2. 链接检测
$link_score = $this->check_links($content);
if ($link_score > 0) {
$score += $link_score;
$reasons[] = '包含可疑链接';
}
// 3. 重复内容检测
$duplicate_score = $this->check_duplicate($content);
if ($duplicate_score > 0) {
$score += $duplicate_score;
$reasons[] = '疑似重复内容';
}
// 4. 用户行为分析
if ($author_id > 0) {
$user_score = $this->check_user_behavior($author_id);
if ($user_score > 0) {
$score += $user_score;
$reasons[] = '用户行为可疑';
}
}
// 5. 模式匹配
$pattern_score = $this->check_patterns($content);
if ($pattern_score > 0) {
$score += $pattern_score;
$reasons[] = '匹配垃圾内容模式';
}
return array(
'score' => $score,
'is_spam' => $score >= 5, // 阈值设为5分
'reasons' => $reasons,
'details' => array(
'keyword_score' => $keyword_score,
'link_score' => $link_score,
'duplicate_score' => $duplicate_score,
'user_score' => $user_score ?? 0,
'pattern_score' => $pattern_score
)
);
}
// 关键词检测
private function check_keywords($content) {
$score = 0;
$content_lower = strtolower($content);
foreach ($this->spam_keywords as $keyword => $weight) {
if (strpos($content_lower, $keyword) !== false) {
$score += $weight;
}
}
return min($score, 3); // 最高3分
}
// 链接检测
private function check_links($content) {
$score = 0;
// 提取所有链接
preg_match_all('/https?://[^s]+/', $content, $matches);
$links = $matches[0] ?? array();
if (count($links) > 3) {
$score += 2; // 链接过多
}
// 检查可疑域名
$suspicious_domains = array('.ru', '.cn', '.xyz', '.top', '.club');
foreach ($links as $link) {
foreach ($suspicious_domains as $domain) {
if (strpos($link, $domain) !== false) {
$score += 1;
break;
}
}
}
return min($score, 3);
}
// 重复内容检测
private function check_duplicate($content) {
global $wpdb;
// 计算内容哈希
$content_hash = md5(trim($content));
// 检查最近24小时内的重复内容
$table_name = $wpdb->prefix . 'ugc_submissions';
$one_day_ago = date('Y-m-d H:i:s', strtotime('-24 hours'));
$count = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $table_name
WHERE MD5(content) = %s
AND created_at > %s",
$content_hash,
$one_day_ago
));
return $count > 0 ? 2 : 0;
}
// 用户行为分析
private function check_user_behavior($user_id) {
global $wpdb;
$score = 0;
$table_name = $wpdb->prefix . 'ugc_submissions';
// 检查用户提交频率
$one_hour_ago = date('Y-m-d H:i:s', strtotime('-1 hour'));
$recent_submissions = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $table_name
WHERE user_id = %d
AND created_at > %s",
$user_id,
$one_hour_ago
));
if ($recent_submissions > 5) {
$score += 2; // 1小时内提交超过5次
}
// 检查用户被拒绝率
$total_submissions = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $table_name WHERE user_id = %d",
$user_id
));
if ($total_submissions > 0) {
$rejected_count = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $table_name
WHERE user_id = %d AND status = 'rejected'",
$user_id
));
$rejection_rate = $rejected_count / $total_submissions;
if ($rejection_rate > 0.5) {
$score += 2; // 拒绝率超过50%
}
}
return min($score, 3);
}
// 模式匹配检测
private function check_patterns($content) {
$score = 0;
foreach ($this->spam_patterns as $pattern => $weight) {
if (preg_match($pattern, $content)) {
$score += $weight;
}
}
return min($score, 2);
}
// 加载垃圾关键词
private function load_spam_keywords() {
// 可以从文件或数据库加载
$this->spam_keywords = array(
'viagra' => 2,
'casino' => 2,
'loan' => 1,
'mortgage' => 1,
'click here' => 1,
'buy now' => 1,
'discount' => 1,
'free' => 1,
'win' => 1,
'prize' => 1,
// 添加更多关键词...
);
}
// 加载垃圾模式
private function load_spam_patterns() {
$this->spam_patterns = array(
'/[A-Z0-9._%+-]+@[A-Z0-9.-]+.[A-Z]{2,}/i' => 1, // 邮箱地址
'/bd{3}[-.]?d{3}[-.]?d{4}b/' => 1, // 电话号码
'/bd{4}[- ]?d{4}[- ]?d{4}[- ]?d{4}b/' => 2, // 信用卡号
'/http:///' => 1, // HTTP链接(非HTTPS)
);
}
}
// 创建审核管理后台页面
class UGC_Admin_Interface {
public function __construct() {
add_action('admin_menu', array($this, 'add_admin_menu'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
add_action('wp_ajax_ugc_bulk_action', array($this, 'handle_bulk_action'));
}
// 添加管理菜单
public function add_admin_menu() {
add_menu_page(
'UGC管理',
'UGC管理',
'manage_options',
'ugc-management',
array($this, 'render_main_page'),
'dashicons-admin-comments',
30
);
add_submenu_page(
'ugc-management',
'内容审核',
'内容审核',
'manage_options',
'ugc-moderation',
array($this, 'render_moderation_page')
);
add_submenu_page(
'ugc-management',
'审核日志',
'审核日志',
'manage_options',
'ugc-logs',
array($this, 'render_logs_page')
);
add_submenu_page(
'ugc-management',
'垃圾检测',
'垃圾检测',
'manage_options',
'ugc-spam',
array($this, 'render_spam_page')
);
add_submenu_page(
'ugc-management',
'用户信誉',
'用户信誉',
'manage_options',
'ugc-reputation',
array($this, 'render_reputation_page')
);
}
// 渲染审核页面
public function render_moderation_page() {
global $wpdb;
$table_name = $wpdb->prefix . 'ugc_submissions';
// 获取筛选参数
$status = isset($_GET['status']) ? sanitize_text_field($_GET['status']) : 'pending';
$type = isset($_GET['type']) ? sanitize_text_field($_GET['type']) : '';
$page = isset($_GET['paged']) ? intval($_GET['paged']) : 1;
$per_page = 20;
$offset = ($page - 1) * $per_page;
// 构建查询
$where = array('1=1');
$params = array();
if ($status) {
$where[] = 'status = %s';
$params[] = $status;
}
if ($type) {
$where[] = 'content_type = %s';
$params[] = $type;
}
$where_clause = implode(' AND ', $where);
// 获取总数
$count_query = "SELECT COUNT(*) FROM $table_name WHERE $where_clause";
if ($params) {
$count_query = $wpdb->prepare($count_query, $params);
}
$total_items = $wpdb->get_var($count_query);
// 获取数据
$data_query = "SELECT * FROM $table_name WHERE $where_clause
ORDER BY created_at DESC LIMIT %d OFFSET %d";
$params[] = $per_page;
$params[] = $offset;
$submissions = $wpdb->get_results($wpdb->prepare($data_query, $params));
?>
<div class="wrap">
<h1 class="wp-heading-inline">内容审核</h1>
<!-- 筛选器 -->
<div class="ugc-filters">
<form method="get" action="">
<input type="hidden" name="page" value="ugc-moderation">
<select name="status" onchange="this.form.submit()">
<option value="">所有状态</option>
<?php
$statuses = array(
'pending' => '待审核',
'under_review' => '审核中',
// 创建审核管理后台页面
class UGC_Admin_Interface {
public function __construct() {
add_action('admin_menu', array($this, 'add_admin_menu'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
add_action('wp_ajax_ugc_bulk_action', array($this, 'handle_bulk_action'));
}
// 添加管理菜单
public function add_admin_menu() {
add_menu_page(
'UGC管理',
'UGC管理',
'manage_options',
'ugc-management',
array($this, 'render_main_page'),
'dashicons-admin-comments',
30
);
add_submenu_page(
'ugc-management',
'内容审核',
'内容审核',
'manage_options',
'ugc-moderation',
array($this, 'render_moderation_page')
);
add_submenu_page(
'ugc-management',
'审核日志',
'审核日志',
'manage_options',
'ugc-logs',
array($this, 'render_logs_page')
);
add_submenu_page(
'ugc-management',
'垃圾检测',
'垃圾检测',
'manage_options',
'ugc-spam',
array($this, 'render_spam_page')
);
add_submenu_page(
'ugc-management',
'用户信誉',
'用户信誉',
'manage_options',
'ugc-reputation',
array($this, 'render_reputation_page')
);
}
// 渲染审核页面
public function render_moderation_page() {
global $wpdb;
$table_name = $wpdb->prefix . 'ugc_submissions';
// 获取筛选参数
$status = isset($_GET['status']) ? sanitize_text_field($_GET['status']) : 'pending';
$type = isset($_GET['type']) ? sanitize_text_field($_GET['type']) : '';
$page = isset($_GET['paged']) ? intval($_GET['paged']) : 1;
$per_page = 20;
$offset = ($page - 1) * $per_page;
// 构建查询
$where = array('1=1');
$params = array();
if ($status) {
$where[] = 'status = %s';
$params[] = $status;
}
if ($type) {
$where[] = 'content_type = %s';
$params[] = $type;
}
$where_clause = implode(' AND ', $where);
// 获取总数
$count_query = "SELECT COUNT(*) FROM $table_name WHERE $where_clause";
if ($params) {
$count_query = $wpdb->prepare($count_query, $params);
}
$total_items = $wpdb->get_var($count_query);
// 获取数据
$data_query = "SELECT * FROM $table_name WHERE $where_clause
ORDER BY created_at DESC LIMIT %d OFFSET %d";
$params[] = $per_page;
$params[] = $offset;
$submissions = $wpdb->get_results($wpdb->prepare($data_query, $params));
?>
<div class="wrap">
<h1 class="wp-heading-inline">内容审核</h1>
<!-- 筛选器 -->
<div class="ugc-filters">
<form method="get" action="">
<input type="hidden" name="page" value="ugc-moderation">
<select name="status" onchange="this.form.submit()">
<option value="">所有状态</option>
<?php
$statuses = array(
'pending' => '待审核',
'under_review' => '审核中',


