文章目录[隐藏]
WordPress开发教程:集成用户反馈收集与需求投票系统
引言:为什么WordPress需要用户反馈系统
在当今互联网时代,用户参与度已成为网站成功的关键因素之一。无论是企业官网、博客还是电子商务平台,了解用户需求、收集反馈意见对于优化用户体验、提升产品价值至关重要。WordPress作为全球最流行的内容管理系统,虽然拥有丰富的插件生态系统,但有时特定需求仍需要通过代码二次开发来实现。
本教程将详细介绍如何在WordPress中通过代码开发集成用户反馈收集与需求投票系统。这种集成不仅能够增强用户参与感,还能为网站优化提供数据支持,帮助站长更好地理解用户需求,从而做出更明智的决策。
系统架构设计
1.1 功能需求分析
在开始编码之前,我们需要明确系统应具备的功能:
- 用户反馈收集:允许用户提交问题、建议或bug报告
- 需求投票系统:用户可以对提出的功能需求进行投票
- 反馈分类管理:将反馈按类型(如功能建议、bug报告、用户体验问题等)分类
- 状态跟踪:跟踪反馈的处理状态(如待处理、已审核、开发中、已解决等)
- 用户通知:当反馈状态更新时通知提交者
- 管理后台:管理员可以查看、管理和回复所有反馈
- 数据统计:提供反馈和投票数据的可视化统计
1.2 数据库设计
我们需要在WordPress数据库中添加以下自定义表:
-- 反馈主表
CREATE TABLE wp_feedback_items (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
type ENUM('feature', 'bug', 'improvement', 'other') DEFAULT 'feature',
status ENUM('pending', 'reviewed', 'planned', 'in_progress', 'completed', 'rejected') DEFAULT 'pending',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES wp_users(ID) ON DELETE SET NULL
);
-- 投票表
CREATE TABLE wp_feedback_votes (
id INT AUTO_INCREMENT PRIMARY KEY,
feedback_id INT NOT NULL,
user_id INT NOT NULL,
vote_type ENUM('up', 'down') DEFAULT 'up',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY unique_vote (feedback_id, user_id),
FOREIGN KEY (feedback_id) REFERENCES wp_feedback_items(id) ON DELETE CASCADE,
FOREIGN KEY (user_id) REFERENCES wp_users(ID) ON DELETE CASCADE
);
-- 评论/回复表
CREATE TABLE wp_feedback_comments (
id INT AUTO_INCREMENT PRIMARY KEY,
feedback_id INT NOT NULL,
user_id INT,
comment TEXT NOT NULL,
is_admin BOOLEAN DEFAULT FALSE,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (feedback_id) REFERENCES wp_feedback_items(id) ON DELETE CASCADE,
FOREIGN KEY (user_id) REFERENCES wp_users(ID) ON DELETE SET NULL
);
开发环境准备
2.1 创建自定义插件
首先,我们需要创建一个独立的WordPress插件来管理所有功能:
<?php
/**
* Plugin Name: WordPress用户反馈与投票系统
* Plugin URI: https://yourwebsite.com/
* Description: 集成用户反馈收集与需求投票系统的WordPress插件
* Version: 1.0.0
* Author: 你的名字
* License: GPL v2 or later
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('WPFB_VERSION', '1.0.0');
define('WPFB_PLUGIN_DIR', plugin_dir_path(__FILE__));
define('WPFB_PLUGIN_URL', plugin_dir_url(__FILE__));
// 初始化插件
require_once WPFB_PLUGIN_DIR . 'includes/class-feedback-system.php';
// 激活和停用钩子
register_activation_hook(__FILE__, array('Feedback_System', 'activate'));
register_deactivation_hook(__FILE__, array('Feedback_System', 'deactivate'));
// 初始化插件
add_action('plugins_loaded', array('Feedback_System', 'get_instance'));
2.2 创建数据库表
在插件激活时创建必要的数据库表:
class Feedback_System {
private static $instance = null;
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
private function __construct() {
$this->init_hooks();
}
private function init_hooks() {
// 初始化数据库
add_action('init', array($this, 'init'));
// 添加管理菜单
add_action('admin_menu', array($this, 'add_admin_menu'));
// 加载脚本和样式
add_action('wp_enqueue_scripts', array($this, 'enqueue_public_scripts'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
// 处理AJAX请求
add_action('wp_ajax_submit_feedback', array($this, 'ajax_submit_feedback'));
add_action('wp_ajax_nopriv_submit_feedback', array($this, 'ajax_submit_feedback'));
add_action('wp_ajax_vote_feedback', array($this, 'ajax_vote_feedback'));
add_action('wp_ajax_nopriv_vote_feedback', array($this, 'ajax_vote_feedback'));
}
public static function activate() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
// 创建反馈表
$feedback_table = $wpdb->prefix . 'feedback_items';
$sql = "CREATE TABLE IF NOT EXISTS $feedback_table (
id INT AUTO_INCREMENT PRIMARY KEY,
user_id INT,
title VARCHAR(255) NOT NULL,
content TEXT NOT NULL,
type VARCHAR(50) DEFAULT 'feature',
status VARCHAR(50) DEFAULT 'pending',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) $charset_collate;";
// 创建投票表
$votes_table = $wpdb->prefix . 'feedback_votes';
$sql .= "CREATE TABLE IF NOT EXISTS $votes_table (
id INT AUTO_INCREMENT PRIMARY KEY,
feedback_id INT NOT NULL,
user_id INT NOT NULL,
vote_type VARCHAR(10) DEFAULT 'up',
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
UNIQUE KEY unique_vote (feedback_id, user_id)
) $charset_collate;";
// 创建评论表
$comments_table = $wpdb->prefix . 'feedback_comments';
$sql .= "CREATE TABLE IF NOT EXISTS $comments_table (
id INT AUTO_INCREMENT PRIMARY KEY,
feedback_id INT NOT NULL,
user_id INT,
comment TEXT NOT NULL,
is_admin BOOLEAN DEFAULT FALSE,
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
// 添加版本号
add_option('wpfb_version', WPFB_VERSION);
}
}
前端反馈表单实现
3.1 创建反馈提交表单
我们需要创建一个用户友好的前端表单,让用户可以轻松提交反馈:
class Feedback_Form {
public static function render_form() {
// 检查用户是否登录
$user_id = get_current_user_id();
$user_name = $user_id ? wp_get_current_user()->display_name : '';
$user_email = $user_id ? wp_get_current_user()->user_email : '';
ob_start();
?>
<div class="feedback-form-container">
<h3>提交反馈或建议</h3>
<?php if (isset($_GET['feedback_submitted']) && $_GET['feedback_submitted'] == 'success'): ?>
<div class="feedback-success">
感谢您的反馈!我们已经收到您的提交。
</div>
<?php endif; ?>
<form id="feedback-form" method="post" action="<?php echo admin_url('admin-ajax.php'); ?>">
<input type="hidden" name="action" value="submit_feedback">
<?php wp_nonce_field('submit_feedback_nonce', 'feedback_nonce'); ?>
<div class="form-group">
<label for="feedback-title">标题 *</label>
<input type="text" id="feedback-title" name="title" required
placeholder="请简要描述您的反馈或建议">
</div>
<div class="form-group">
<label for="feedback-type">反馈类型 *</label>
<select id="feedback-type" name="type" required>
<option value="">请选择类型</option>
<option value="feature">功能建议</option>
<option value="bug">错误报告</option>
<option value="improvement">改进建议</option>
<option value="other">其他</option>
</select>
</div>
<div class="form-group">
<label for="feedback-content">详细描述 *</label>
<textarea id="feedback-content" name="content" rows="6" required
placeholder="请详细描述您的反馈或建议..."></textarea>
</div>
<?php if (!$user_id): ?>
<div class="form-row">
<div class="form-group">
<label for="feedback-name">您的姓名 *</label>
<input type="text" id="feedback-name" name="user_name" required>
</div>
<div class="form-group">
<label for="feedback-email">电子邮箱 *</label>
<input type="email" id="feedback-email" name="user_email" required>
</div>
</div>
<?php endif; ?>
<div class="form-group">
<button type="submit" class="submit-feedback-btn">提交反馈</button>
<div class="form-loading" style="display:none;">
提交中,请稍候...
</div>
</div>
</form>
</div>
<script>
jQuery(document).ready(function($) {
$('#feedback-form').on('submit', function(e) {
e.preventDefault();
var form = $(this);
var submitBtn = form.find('.submit-feedback-btn');
var loading = form.find('.form-loading');
// 验证表单
if (!form[0].checkValidity()) {
form[0].reportValidity();
return;
}
// 显示加载状态
submitBtn.prop('disabled', true);
loading.show();
// 收集表单数据
var formData = new FormData(this);
// 发送AJAX请求
$.ajax({
url: '<?php echo admin_url("admin-ajax.php"); ?>',
type: 'POST',
data: formData,
processData: false,
contentType: false,
success: function(response) {
if (response.success) {
// 提交成功,重定向到成功页面
window.location.href = window.location.href + '?feedback_submitted=success';
} else {
alert(response.data || '提交失败,请重试。');
submitBtn.prop('disabled', false);
loading.hide();
}
},
error: function() {
alert('网络错误,请重试。');
submitBtn.prop('disabled', false);
loading.hide();
}
});
});
});
</script>
<?php
return ob_get_clean();
}
}
3.2 创建短代码
为了让用户可以在任何文章或页面中插入反馈表单,我们创建一个短代码:
// 在Feedback_System类中添加短代码注册
add_shortcode('feedback_form', array($this, 'feedback_form_shortcode'));
public function feedback_form_shortcode($atts) {
$atts = shortcode_atts(array(
'title' => '提交反馈',
'show_type' => true
), $atts, 'feedback_form');
return Feedback_Form::render_form();
}
现在用户可以在文章或页面中使用 [feedback_form] 短代码来显示反馈表单。
需求投票系统实现
4.1 创建投票界面
投票系统允许用户对已有的反馈进行投票,帮助确定需求的优先级:
class Voting_System {
public static function render_voting_section($feedback_id = null) {
global $wpdb;
if (!$feedback_id) {
return '';
}
$user_id = get_current_user_id();
$table_name = $wpdb->prefix . 'feedback_items';
$votes_table = $wpdb->prefix . 'feedback_votes';
// 获取反馈详情
$feedback = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM $table_name WHERE id = %d", $feedback_id
));
if (!$feedback) {
return '';
}
// 获取投票统计
$upvotes = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $votes_table WHERE feedback_id = %d AND vote_type = 'up'",
$feedback_id
));
$downvotes = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $votes_table WHERE feedback_id = %d AND vote_type = 'down'",
$feedback_id
));
// 检查当前用户是否已投票
$user_vote = null;
if ($user_id) {
$user_vote = $wpdb->get_var($wpdb->prepare(
"SELECT vote_type FROM $votes_table WHERE feedback_id = %d AND user_id = %d",
$feedback_id, $user_id
));
}
ob_start();
?>
<div class="feedback-voting" data-feedback-id="<?php echo esc_attr($feedback_id); ?>">
<div class="vote-count">
<span class="vote-total"><?php echo ($upvotes - $downvotes); ?></span>
<span class="vote-label">票</span>
</div>
<div class="vote-buttons">
<button class="vote-btn vote-up <?php echo ($user_vote == 'up') ? 'voted' : ''; ?>"
data-vote-type="up"
<?php echo (!$user_id) ? 'disabled title="请登录后投票"' : ''; ?>>
<span class="dashicons dashicons-thumbs-up"></span>
<span class="vote-count"><?php echo $upvotes; ?></span>
</button>
<button class="vote-btn vote-down <?php echo ($user_vote == 'down') ? 'voted' : ''; ?>"
data-vote-type="down"
<?php echo (!$user_id) ? 'disabled title="请登录后投票"' : ''; ?>>
<span class="dashicons dashicons-thumbs-down"></span>
<span class="vote-count"><?php echo $downvotes; ?></span>
</button>
</div>
<?php if (!$user_id): ?>
<p class="vote-login-notice">请<a href="<?php echo wp_login_url(get_permalink()); ?>">登录</a>后投票</p>
<?php endif; ?>
</div>
<script>
jQuery(document).ready(function($) {
$('.vote-btn').on('click', function(e) {
e.preventDefault();
var button = $(this);
var feedbackId = button.closest('.feedback-voting').data('feedback-id');
var voteType = button.data('vote-type');
// 如果已经投票,则取消投票
if (button.hasClass('voted')) {
var newVoteType = null;
} else {
var newVoteType = voteType;
}
$.ajax({
url: '<?php echo admin_url("admin-ajax.php"); ?>',
type: 'POST',
data: {
action: 'vote_feedback',
feedback_id: feedbackId,
vote_type: newVoteType,
nonce: '<?php echo wp_create_nonce("vote_feedback_nonce"); ?>'
},
success: function(response) {
if (response.success) {
// 更新UI
var votingSection = button.closest('.feedback-voting');
votingSection.find('.vote-total').text(response.data.total_votes);
votingSection.find('.vote-up .vote-count').text(response.data.upvotes);
votingSection.find('.vote-down .vote-count').text(response.data.downvotes);
// 更新按钮状态
votingSection.find('.vote-btn').removeClass('voted');
if (newVoteType) {
votingSection.find('.vote-btn[data-vote-type="' + newVoteType + '"]').addClass('voted');
}
} else {
alert(response.data || '投票失败,请重试。');
}
}
});
});
});
</script>
<?php
return ob_get_clean();
}
}
4.2 处理投票的AJAX请求
// 在Feedback_System类中添加投票处理
public function ajax_vote_feedback() {
// 验证nonce
if (!wp_verify_nonce($_POST['nonce'], 'vote_feedback_nonce')) {
wp_die('安全验证失败');
}
$user_id = get_current_user_id();
if (!$user_id) {
wp_send_json_error('请登录后投票');
}
$feedback_id = intval($_POST['feedback_id']);
$vote_type = $_POST['vote_type'] ? sanitize_text_field($_POST['vote_type']) : null;
global $wpdb;
$votes_table = $wpdb->prefix . 'feedback_votes';
// 检查是否已投票
$existing_vote = $wpdb->get_row($wpdb->prepare(
WordPress开发教程:集成用户反馈收集与需求投票系统(续)
投票系统实现(续)
4.3 处理投票的AJAX请求(续)
// 在Feedback_System类中添加投票处理
public function ajax_vote_feedback() {
// 验证nonce
if (!wp_verify_nonce($_POST['nonce'], 'vote_feedback_nonce')) {
wp_die('安全验证失败');
}
$user_id = get_current_user_id();
if (!$user_id) {
wp_send_json_error('请登录后投票');
}
$feedback_id = intval($_POST['feedback_id']);
$vote_type = $_POST['vote_type'] ? sanitize_text_field($_POST['vote_type']) : null;
global $wpdb;
$votes_table = $wpdb->prefix . 'feedback_votes';
// 检查是否已投票
$existing_vote = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM $votes_table WHERE feedback_id = %d AND user_id = %d",
$feedback_id, $user_id
));
if ($existing_vote) {
if ($vote_type) {
// 更新现有投票
$wpdb->update(
$votes_table,
array('vote_type' => $vote_type, 'created_at' => current_time('mysql')),
array('id' => $existing_vote->id)
);
} else {
// 删除投票(取消投票)
$wpdb->delete(
$votes_table,
array('id' => $existing_vote->id)
);
}
} else {
if ($vote_type) {
// 插入新投票
$wpdb->insert(
$votes_table,
array(
'feedback_id' => $feedback_id,
'user_id' => $user_id,
'vote_type' => $vote_type,
'created_at' => current_time('mysql')
)
);
}
}
// 重新计算投票统计
$upvotes = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $votes_table WHERE feedback_id = %d AND vote_type = 'up'",
$feedback_id
));
$downvotes = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $votes_table WHERE feedback_id = %d AND vote_type = 'down'",
$feedback_id
));
$total_votes = $upvotes - $downvotes;
wp_send_json_success(array(
'total_votes' => $total_votes,
'upvotes' => $upvotes,
'downvotes' => $downvotes
));
}
反馈列表与展示页面
5.1 创建反馈列表页面
用户需要能够查看所有提交的反馈并进行投票:
class Feedback_List {
public static function render_feedback_list($atts = array()) {
global $wpdb;
$atts = shortcode_atts(array(
'type' => 'all',
'status' => 'all',
'per_page' => 10,
'show_voting' => true,
'show_filters' => true
), $atts, 'feedback_list');
$page = isset($_GET['fb_page']) ? max(1, intval($_GET['fb_page'])) : 1;
$offset = ($page - 1) * $atts['per_page'];
$table_name = $wpdb->prefix . 'feedback_items';
$votes_table = $wpdb->prefix . 'feedback_votes';
// 构建查询条件
$where_conditions = array('1=1');
$query_params = array();
if ($atts['type'] != 'all') {
$where_conditions[] = "type = %s";
$query_params[] = $atts['type'];
}
if ($atts['status'] != 'all') {
$where_conditions[] = "status = %s";
$query_params[] = $atts['status'];
}
$where_clause = implode(' AND ', $where_conditions);
// 获取总数量
$count_query = "SELECT COUNT(*) FROM $table_name WHERE $where_clause";
if ($query_params) {
$count_query = $wpdb->prepare($count_query, $query_params);
}
$total_items = $wpdb->get_var($count_query);
$total_pages = ceil($total_items / $atts['per_page']);
// 获取反馈列表
$query = "SELECT f.*,
COUNT(CASE WHEN v.vote_type = 'up' THEN 1 END) as upvotes,
COUNT(CASE WHEN v.vote_type = 'down' THEN 1 END) as downvotes
FROM $table_name f
LEFT JOIN $votes_table v ON f.id = v.feedback_id
WHERE $where_clause
GROUP BY f.id
ORDER BY (upvotes - downvotes) DESC, f.created_at DESC
LIMIT %d OFFSET %d";
$query_params[] = $atts['per_page'];
$query_params[] = $offset;
$feedback_items = $wpdb->get_results($wpdb->prepare($query, $query_params));
ob_start();
?>
<div class="feedback-list-container">
<?php if ($atts['show_filters']): ?>
<div class="feedback-filters">
<form method="get" class="filter-form">
<input type="hidden" name="fb_page" value="1">
<div class="filter-group">
<label for="filter-type">反馈类型:</label>
<select id="filter-type" name="fb_type" onchange="this.form.submit()">
<option value="all" <?php selected($atts['type'], 'all'); ?>>全部类型</option>
<option value="feature" <?php selected($atts['type'], 'feature'); ?>>功能建议</option>
<option value="bug" <?php selected($atts['type'], 'bug'); ?>>错误报告</option>
<option value="improvement" <?php selected($atts['type'], 'improvement'); ?>>改进建议</option>
</select>
</div>
<div class="filter-group">
<label for="filter-status">状态:</label>
<select id="filter-status" name="fb_status" onchange="this.form.submit()">
<option value="all" <?php selected($atts['status'], 'all'); ?>>全部状态</option>
<option value="pending" <?php selected($atts['status'], 'pending'); ?>>待处理</option>
<option value="reviewed" <?php selected($atts['status'], 'reviewed'); ?>>已审核</option>
<option value="planned" <?php selected($atts['status'], 'planned'); ?>>计划中</option>
<option value="in_progress" <?php selected($atts['status'], 'in_progress'); ?>>开发中</option>
<option value="completed" <?php selected($atts['status'], 'completed'); ?>>已完成</option>
</select>
</div>
<button type="submit" class="filter-btn">筛选</button>
</form>
</div>
<?php endif; ?>
<div class="feedback-items">
<?php if (empty($feedback_items)): ?>
<div class="no-feedback">
<p>暂无反馈记录</p>
</div>
<?php else: ?>
<?php foreach ($feedback_items as $item): ?>
<?php echo self::render_feedback_item($item, $atts['show_voting']); ?>
<?php endforeach; ?>
<?php endif; ?>
</div>
<?php if ($total_pages > 1): ?>
<div class="feedback-pagination">
<?php
echo paginate_links(array(
'base' => add_query_arg('fb_page', '%#%'),
'format' => '',
'prev_text' => '«',
'next_text' => '»',
'total' => $total_pages,
'current' => $page,
'add_args' => array(
'fb_type' => $atts['type'],
'fb_status' => $atts['status']
)
));
?>
</div>
<?php endif; ?>
</div>
<?php
return ob_get_clean();
}
private static function render_feedback_item($item, $show_voting = true) {
$type_labels = array(
'feature' => '功能建议',
'bug' => '错误报告',
'improvement' => '改进建议',
'other' => '其他'
);
$status_labels = array(
'pending' => array('label' => '待处理', 'class' => 'status-pending'),
'reviewed' => array('label' => '已审核', 'class' => 'status-reviewed'),
'planned' => array('label' => '计划中', 'class' => 'status-planned'),
'in_progress' => array('label' => '开发中', 'class' => 'status-in-progress'),
'completed' => array('label' => '已完成', 'class' => 'status-completed'),
'rejected' => array('label' => '已拒绝', 'class' => 'status-rejected')
);
$user_info = $item->user_id ? get_userdata($item->user_id) : null;
$user_name = $user_info ? $user_info->display_name : '匿名用户';
$user_avatar = $user_info ? get_avatar($item->user_id, 40) : get_avatar(0, 40);
$total_votes = $item->upvotes - $item->downvotes;
ob_start();
?>
<div class="feedback-item" id="feedback-<?php echo $item->id; ?>">
<div class="feedback-header">
<div class="user-info">
<div class="user-avatar">
<?php echo $user_avatar; ?>
</div>
<div class="user-details">
<span class="user-name"><?php echo esc_html($user_name); ?></span>
<span class="feedback-date"><?php echo date('Y-m-d H:i', strtotime($item->created_at)); ?></span>
</div>
</div>
<div class="feedback-meta">
<span class="feedback-type type-<?php echo $item->type; ?>">
<?php echo $type_labels[$item->type]; ?>
</span>
<span class="feedback-status <?php echo $status_labels[$item->status]['class']; ?>">
<?php echo $status_labels[$item->status]['label']; ?>
</span>
</div>
</div>
<div class="feedback-content">
<h3 class="feedback-title"><?php echo esc_html($item->title); ?></h3>
<div class="feedback-description">
<?php echo wpautop(esc_html($item->content)); ?>
</div>
</div>
<div class="feedback-footer">
<?php if ($show_voting): ?>
<div class="feedback-voting-section">
<?php echo Voting_System::render_voting_section($item->id); ?>
</div>
<?php endif; ?>
<div class="feedback-actions">
<a href="<?php echo add_query_arg('feedback_id', $item->id, get_permalink()); ?>"
class="view-details-btn">
查看详情
</a>
<?php if (current_user_can('manage_options') || get_current_user_id() == $item->user_id): ?>
<button class="add-comment-btn" data-feedback-id="<?php echo $item->id; ?>">
添加评论
</button>
<?php endif; ?>
</div>
</div>
<?php echo self::render_comments_section($item->id); ?>
</div>
<?php
return ob_get_clean();
}
}
5.2 添加短代码支持
// 在Feedback_System类中添加短代码
add_shortcode('feedback_list', array($this, 'feedback_list_shortcode'));
public function feedback_list_shortcode($atts) {
return Feedback_List::render_feedback_list($atts);
}
管理后台界面开发
6.1 创建管理菜单和页面
class Feedback_Admin {
public static function add_admin_menu() {
// 主菜单
add_menu_page(
'用户反馈管理',
'用户反馈',
'manage_options',
'feedback-management',
array(__CLASS__, 'render_admin_page'),
'dashicons-feedback',
30
);
// 子菜单
add_submenu_page(
'feedback-management',
'所有反馈',
'所有反馈',
'manage_options',
'feedback-management',
array(__CLASS__, 'render_admin_page')
);
add_submenu_page(
'feedback-management',
'反馈统计',
'统计报表',
'manage_options',
'feedback-statistics',
array(__CLASS__, 'render_statistics_page')
);
add_submenu_page(
'feedback-management',
'反馈设置',
'设置',
'manage_options',
'feedback-settings',
array(__CLASS__, 'render_settings_page')
);
}
public static function render_admin_page() {
global $wpdb;
$table_name = $wpdb->prefix . 'feedback_items';
$votes_table = $wpdb->prefix . 'feedback_votes';
// 处理批量操作
if (isset($_POST['bulk_action']) && isset($_POST['feedback_ids'])) {
self::handle_bulk_actions($_POST['bulk_action'], $_POST['feedback_ids']);
}
// 处理单个操作
if (isset($_GET['action']) && isset($_GET['feedback_id'])) {
self::handle_single_action($_GET['action'], $_GET['feedback_id']);
}
// 分页参数
$per_page = 20;
$page = isset($_GET['paged']) ? max(1, intval($_GET['paged'])) : 1;
$offset = ($page - 1) * $per_page;
// 搜索和筛选条件
$where_conditions = array('1=1');
$query_params = array();
if (!empty($_GET['s'])) {
$where_conditions[] = "(title LIKE %s OR content LIKE %s)";
$search_term = '%' . $wpdb->esc_like($_GET['s']) . '%';
$query_params[] = $search_term;
$query_params[] = $search_term;
}
if (!empty($_GET['type'])) {
$where_conditions[] = "type = %s";
$query_params[] = $_GET['type'];
}
if (!empty($_GET['status'])) {
$where_conditions[] = "status = %s";
$query_params[] = $_GET['status'];
}
$where_clause = implode(' AND ', $where_conditions);
// 获取总数
$count_query = "SELECT COUNT(*) FROM $table_name WHERE $where_clause";
if ($query_params) {
$count_query = $wpdb->prepare($count_query, $query_params);
}
$total_items = $wpdb->get_var($count_query);
$total_pages = ceil($total_items / $per_page);
// 获取数据
$query = "SELECT f.*,
u.user_login, u.display_name, u.user_email,
COUNT(CASE WHEN v.vote_type = 'up' THEN 1 END) as upvotes,
COUNT(CASE WHEN v.vote_type = 'down' THEN 1 END) as downvotes
FROM $table_name f
LEFT JOIN {$wpdb->users} u ON f.user_id = u.ID
LEFT JOIN $votes_table v ON f.id = v.feedback_id
WHERE $where_clause
GROUP BY f.id
ORDER BY f.created_at DESC
LIMIT %d OFFSET %d";
$query_params[] = $per_page;
$query_params[] = $offset;
$feedback_items = $wpdb->get_results($wpdb->prepare($query, $query_params));
?>
<div class="wrap">
<h1 class="wp-heading-inline">用户反馈管理</h1>
<form method="get" class="search-form">
<input type="hidden" name="page" value="feedback-management">
<div class="tablenav top">
<div class="alignleft actions bulkactions">
<select name="bulk_action">
<option value="">批量操作</option>
<option value="mark_reviewed">标记为已审核</option>
<option value="mark_in_progress">标记为开发中</option>
<option value="mark_completed">标记为已完成</option>
<option value="delete">删除</option>
</select>
<button type="submit" class="button action">应用</button>
</div>
<div class="alignleft actions">
<select name="type">
<option value="">所有类型</option>
<option value="feature" <?php selected(@$_GET['type'], 'feature'); ?>>功能建议</option>
<option value="bug" <?php selected(@$_GET['type'], 'bug'); ?>>错误报告</option>
<option value="improvement" <?php selected(@$_GET['type'], 'improvement'); ?>>改进建议</option>
</select>
<select name="status">
<option value="">所有状态</option>
<option value="pending" <?php selected(@$_GET['status'], 'pending'); ?>>待处理</option>
