From 0dba91c5755aabb617d24785517f922118fb9fe6 Mon Sep 17 00:00:00 2001 From: nanhaoluo <3075912108@qq.com> Date: Fri, 16 Jan 2026 22:36:21 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=E9=97=AE=E9=A2=98?= =?UTF-8?q?=E5=8F=8D=E9=A6=88=E9=A1=B5=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 支持公开/私密反馈,公开反馈所有人可见 - 必填邮箱和昵称,支持从 Cookie 自动填充 - 反馈类型:建议、Bug、问题咨询、其他 - 管理员可回复反馈,回复后邮件通知用户 - 管理员可切换公开状态、更新处理状态、删除反馈 - 状态管理:待处理、处理中、已解决、已关闭 - 支持验证码防刷 - 页面样式参考友情链接页面 --- feedback.php | 810 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 810 insertions(+) create mode 100644 feedback.php diff --git a/feedback.php b/feedback.php new file mode 100644 index 0000000..8ce87bd --- /dev/null +++ b/feedback.php @@ -0,0 +1,810 @@ + false, 'message' => '']; + $action = sanitize_text_field($_POST['feedback_action']); + + // 管理员操作 + if (in_array($action, ['delete', 'toggle_public', 'reply', 'update_status'])) { + if (!$is_admin) { + echo json_encode(['success' => false, 'message' => '权限不足']); + exit; + } + if (!isset($_POST['feedback_nonce']) || !wp_verify_nonce($_POST['feedback_nonce'], 'argon_feedback_manage')) { + echo json_encode(['success' => false, 'message' => '安全验证失败']); + exit; + } + } + + switch ($action) { + case 'submit': + $response = argon_handle_feedback_submit($_POST); + break; + case 'delete': + $id = isset($_POST['id']) ? sanitize_text_field($_POST['id']) : ''; + $response = ['success' => argon_delete_feedback($id)]; + break; + case 'toggle_public': + $id = isset($_POST['id']) ? sanitize_text_field($_POST['id']) : ''; + $response = argon_toggle_feedback_public($id); + break; + case 'reply': + $id = isset($_POST['id']) ? sanitize_text_field($_POST['id']) : ''; + $reply = isset($_POST['reply']) ? sanitize_textarea_field($_POST['reply']) : ''; + $response = argon_reply_feedback($id, $reply); + break; + case 'update_status': + $id = isset($_POST['id']) ? sanitize_text_field($_POST['id']) : ''; + $status = isset($_POST['status']) ? sanitize_text_field($_POST['status']) : ''; + $response = argon_update_feedback_status($id, $status); + break; + } + echo json_encode($response); + exit; +} + +// ==================== 反馈数据操作函数 ==================== + +/** + * 获取用户唯一标识 + */ +function argon_get_feedback_user_identifier() { + if (is_user_logged_in()) { + return 'user_' . get_current_user_id(); + } + $ip = ''; + if (!empty($_SERVER['HTTP_CLIENT_IP'])) { + $ip = $_SERVER['HTTP_CLIENT_IP']; + } elseif (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) { + $ip_list = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']); + $ip = trim($ip_list[0]); + } elseif (!empty($_SERVER['HTTP_X_REAL_IP'])) { + $ip = $_SERVER['HTTP_X_REAL_IP']; + } else { + $ip = $_SERVER['REMOTE_ADDR']; + } + $user_agent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : ''; + return substr(hash('sha256', $ip . '|' . $user_agent), 0, 16); +} + +/** + * 获取所有反馈 + */ +function argon_get_feedbacks($filter = 'all') { + $feedbacks = get_option('argon_feedbacks', []); + if (!is_array($feedbacks)) $feedbacks = []; + + // 按时间倒序 + usort($feedbacks, function($a, $b) { + return ($b['created_at'] ?? 0) - ($a['created_at'] ?? 0); + }); + + if ($filter === 'public') { + return array_filter($feedbacks, function($f) { + return !empty($f['is_public']); + }); + } + return $feedbacks; +} + +/** + * 获取单个反馈 + */ +function argon_get_feedback($id) { + $feedbacks = argon_get_feedbacks(); + foreach ($feedbacks as $f) { + if ($f['id'] === $id) return $f; + } + return null; +} + + +/** + * 添加反馈 + */ +function argon_add_feedback($data) { + $feedbacks = get_option('argon_feedbacks', []); + if (!is_array($feedbacks)) $feedbacks = []; + + $id = 'fb_' . uniqid(); + $feedback = [ + 'id' => $id, + 'title' => sanitize_text_field($data['title'] ?? ''), + 'content' => sanitize_textarea_field($data['content'] ?? ''), + 'type' => sanitize_text_field($data['type'] ?? 'suggestion'), + 'name' => sanitize_text_field($data['name'] ?? ''), + 'email' => sanitize_email($data['email'] ?? ''), + 'url' => esc_url_raw($data['url'] ?? ''), + 'is_public' => !empty($data['is_public']), + 'status' => 'pending', // pending, processing, resolved, closed + 'user_identifier' => argon_get_feedback_user_identifier(), + 'user_id' => is_user_logged_in() ? get_current_user_id() : 0, + 'ip' => $_SERVER['REMOTE_ADDR'] ?? '', + 'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? '', + 'created_at' => time(), + 'reply' => '', + 'reply_at' => 0, + ]; + + $feedbacks[] = $feedback; + update_option('argon_feedbacks', $feedbacks); + + return $id; +} + +/** + * 删除反馈 + */ +function argon_delete_feedback($id) { + $feedbacks = get_option('argon_feedbacks', []); + if (!is_array($feedbacks)) return false; + + foreach ($feedbacks as $key => $f) { + if ($f['id'] === $id) { + unset($feedbacks[$key]); + update_option('argon_feedbacks', array_values($feedbacks)); + return true; + } + } + return false; +} + +/** + * 切换公开状态 + */ +function argon_toggle_feedback_public($id) { + $feedbacks = get_option('argon_feedbacks', []); + if (!is_array($feedbacks)) return ['success' => false]; + + foreach ($feedbacks as &$f) { + if ($f['id'] === $id) { + $f['is_public'] = !$f['is_public']; + update_option('argon_feedbacks', $feedbacks); + return ['success' => true, 'is_public' => $f['is_public']]; + } + } + return ['success' => false]; +} + + +/** + * 回复反馈 + */ +function argon_reply_feedback($id, $reply) { + $feedbacks = get_option('argon_feedbacks', []); + if (!is_array($feedbacks)) return ['success' => false]; + + foreach ($feedbacks as &$f) { + if ($f['id'] === $id) { + $f['reply'] = $reply; + $f['reply_at'] = time(); + if ($f['status'] === 'pending') { + $f['status'] = 'processing'; + } + update_option('argon_feedbacks', $feedbacks); + + // 发送邮件通知 + if (!empty($f['email']) && !empty($reply)) { + $subject = sprintf('[%s] 您的反馈已收到回复', get_bloginfo('name')); + $message = sprintf( + "您好 %s!\n\n您提交的反馈「%s」已收到回复:\n\n%s\n\n感谢您的反馈!\n\n%s", + $f['name'], + $f['title'], + $reply, + home_url() + ); + wp_mail($f['email'], $subject, $message); + } + + return ['success' => true]; + } + } + return ['success' => false]; +} + +/** + * 更新反馈状态 + */ +function argon_update_feedback_status($id, $status) { + $valid_statuses = ['pending', 'processing', 'resolved', 'closed']; + if (!in_array($status, $valid_statuses)) { + return ['success' => false, 'message' => '无效状态']; + } + + $feedbacks = get_option('argon_feedbacks', []); + if (!is_array($feedbacks)) return ['success' => false]; + + foreach ($feedbacks as &$f) { + if ($f['id'] === $id) { + $f['status'] = $status; + update_option('argon_feedbacks', $feedbacks); + return ['success' => true]; + } + } + return ['success' => false]; +} + +/** + * 处理反馈提交 + */ +function argon_handle_feedback_submit($data) { + // 验证必填字段 + if (empty($data['feedback_email'])) { + return ['success' => false, 'message' => __('请填写邮箱', 'argon')]; + } + if (empty($data['feedback_name'])) { + return ['success' => false, 'message' => __('请填写昵称', 'argon')]; + } + if (empty($data['feedback_content'])) { + return ['success' => false, 'message' => __('请填写反馈内容', 'argon')]; + } + + // 验证邮箱格式 + if (!is_email($data['feedback_email'])) { + return ['success' => false, 'message' => __('邮箱格式错误', 'argon')]; + } + + // 验证码检查 + $captcha_enabled = get_option('argon_feedback_captcha', 'true') === 'true'; + if ($captcha_enabled && function_exists('check_comment_captcha')) { + $captcha_input = $data['feedback_captcha'] ?? ''; + if (!check_comment_captcha($captcha_input)) { + return ['success' => false, 'message' => __('验证码错误', 'argon')]; + } + } + + // 添加反馈 + $id = argon_add_feedback([ + 'title' => $data['feedback_title'] ?? '', + 'content' => $data['feedback_content'], + 'type' => $data['feedback_type'] ?? 'suggestion', + 'name' => $data['feedback_name'], + 'email' => $data['feedback_email'], + 'url' => $data['feedback_url'] ?? '', + 'is_public' => !empty($data['feedback_public']), + ]); + + if ($id) { + return ['success' => true, 'message' => __('反馈提交成功,感谢您的建议!', 'argon')]; + } + return ['success' => false, 'message' => __('提交失败,请稍后重试', 'argon')]; +} + + +// ==================== 页面渲染 ==================== + +// 获取反馈数据 +$all_feedbacks = argon_get_feedbacks(); +$public_feedbacks = argon_get_feedbacks('public'); +$pending_count = count(array_filter($all_feedbacks, function($f) { return $f['status'] === 'pending'; })); + +// 验证码设置 +$captcha_enabled = get_option('argon_feedback_captcha', 'true') === 'true'; + +// 从 Cookie 获取用户信息 +$saved_name = isset($_COOKIE['comment_author_' . COOKIEHASH]) ? $_COOKIE['comment_author_' . COOKIEHASH] : ''; +$saved_email = isset($_COOKIE['comment_author_email_' . COOKIEHASH]) ? $_COOKIE['comment_author_email_' . COOKIEHASH] : ''; +$saved_url = isset($_COOKIE['comment_author_url_' . COOKIEHASH]) ? $_COOKIE['comment_author_url_' . COOKIEHASH] : ''; + +// 如果已登录,使用用户信息 +if (is_user_logged_in()) { + $current_user = wp_get_current_user(); + $saved_name = $current_user->display_name; + $saved_email = $current_user->user_email; + $saved_url = $current_user->user_url; +} + +get_header(); +?> + +
+ + +