文章目录[隐藏]
WordPress网站活动抽奖与互动游戏化组件开发详细教程
引言:为什么WordPress网站需要游戏化组件
在当今互联网环境中,用户参与度和互动性已成为网站成功的关键指标。无论是电商平台、内容网站还是企业官网,通过游戏化元素如抽奖、积分系统、进度条等互动组件,可以显著提升用户粘性、延长停留时间并促进转化。WordPress作为全球最流行的内容管理系统,拥有强大的扩展能力,通过代码二次开发,我们可以为网站添加各种互联网常用的小工具功能。
本教程将详细指导您如何为WordPress网站开发活动抽奖与互动游戏化组件,从环境搭建到功能实现,涵盖完整的技术流程。无论您是WordPress开发者还是有一定技术基础的网站管理员,都能通过本教程掌握相关技能。
第一章:开发环境准备与基础架构
1.1 开发环境配置
在开始开发之前,我们需要准备合适的开发环境:
- 本地开发环境:推荐使用XAMPP、MAMP或Local by Flywheel
- WordPress安装:最新版本的WordPress(建议5.8+)
- 代码编辑器:VS Code、Sublime Text或PHPStorm
- 浏览器开发者工具:Chrome DevTools或Firefox Developer Tools
1.2 创建自定义插件
为了避免主题更新导致功能丢失,我们将创建一个独立的插件来实现所有功能:
<?php
/**
* Plugin Name: 互动游戏化组件套件
* Plugin URI: https://yourwebsite.com/
* Description: 为WordPress网站添加抽奖、游戏化互动功能
* Version: 1.0.0
* Author: Your Name
* License: GPL v2 or later
*/
// 防止直接访问
if (!defined('ABSPATH')) {
exit;
}
// 定义插件常量
define('GAMIFICATION_PLUGIN_PATH', plugin_dir_path(__FILE__));
define('GAMIFICATION_PLUGIN_URL', plugin_dir_url(__FILE__));
define('GAMIFICATION_VERSION', '1.0.0');
// 初始化插件
require_once GAMIFICATION_PLUGIN_PATH . 'includes/class-gamification-core.php';
function run_gamification_plugin() {
$plugin = new Gamification_Core();
$plugin->run();
}
run_gamification_plugin();
1.3 数据库表设计
我们需要创建几个数据库表来存储游戏化组件的数据:
// 在插件激活时创建数据库表
register_activation_hook(__FILE__, 'gamification_create_tables');
function gamification_create_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
// 抽奖活动表
$table_name = $wpdb->prefix . 'gamification_lotteries';
$sql = "CREATE TABLE IF NOT EXISTS $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
title varchar(200) NOT NULL,
description text,
start_date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
end_date datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
status varchar(20) DEFAULT 'draft',
settings longtext,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id)
) $charset_collate;";
// 抽奖奖品表
$table_name_prizes = $wpdb->prefix . 'gamification_prizes';
$sql2 = "CREATE TABLE IF NOT EXISTS $table_name_prizes (
id mediumint(9) NOT NULL AUTO_INCREMENT,
lottery_id mediumint(9) NOT NULL,
name varchar(200) NOT NULL,
description text,
image_url varchar(500),
quantity int NOT NULL DEFAULT 1,
probability decimal(5,4) NOT NULL DEFAULT 0.0,
remaining int NOT NULL DEFAULT 0,
type varchar(50) DEFAULT 'physical',
PRIMARY KEY (id),
KEY lottery_id (lottery_id)
) $charset_collate;";
// 用户参与记录表
$table_name_participants = $wpdb->prefix . 'gamification_participants';
$sql3 = "CREATE TABLE IF NOT EXISTS $table_name_participants (
id mediumint(9) NOT NULL AUTO_INCREMENT,
user_id bigint(20) unsigned,
lottery_id mediumint(9) NOT NULL,
prize_id mediumint(9),
win_status varchar(20) DEFAULT 'pending',
participant_data longtext,
ip_address varchar(45),
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY user_id (user_id),
KEY lottery_id (lottery_id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
dbDelta($sql2);
dbDelta($sql3);
}
第二章:抽奖系统核心功能开发
2.1 抽奖活动管理后台
首先创建抽奖活动的管理界面:
// 在includes/class-gamification-admin.php中
class Gamification_Admin {
public function __construct() {
add_action('admin_menu', array($this, 'add_admin_menu'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
}
public function add_admin_menu() {
add_menu_page(
'游戏化组件',
'游戏化组件',
'manage_options',
'gamification',
array($this, 'display_main_page'),
'dashicons-games',
30
);
add_submenu_page(
'gamification',
'抽奖活动',
'抽奖活动',
'manage_options',
'gamification-lotteries',
array($this, 'display_lotteries_page')
);
add_submenu_page(
'gamification',
'添加新抽奖',
'添加新抽奖',
'manage_options',
'gamification-add-lottery',
array($this, 'display_add_lottery_page')
);
}
public function display_lotteries_page() {
include GAMIFICATION_PLUGIN_PATH . 'admin/views/lotteries-list.php';
}
public function display_add_lottery_page() {
include GAMIFICATION_PLUGIN_PATH . 'admin/views/lottery-edit.php';
}
public function enqueue_admin_scripts($hook) {
if (strpos($hook, 'gamification') !== false) {
wp_enqueue_style('gamification-admin', GAMIFICATION_PLUGIN_URL . 'assets/css/admin.css', array(), GAMIFICATION_VERSION);
wp_enqueue_script('gamification-admin', GAMIFICATION_PLUGIN_URL . 'assets/js/admin.js', array('jquery', 'jquery-ui-sortable'), GAMIFICATION_VERSION, true);
// 本地化脚本
wp_localize_script('gamification-admin', 'gamification_ajax', array(
'ajax_url' => admin_url('admin-ajax.php'),
'nonce' => wp_create_nonce('gamification_nonce')
));
}
}
}
2.2 抽奖活动前端展示
创建前端抽奖界面:
// 短代码处理
add_shortcode('lottery_wheel', 'gamification_lottery_wheel_shortcode');
function gamification_lottery_wheel_shortcode($atts) {
$atts = shortcode_atts(array(
'id' => 0,
'title' => '幸运大转盘',
'width' => '500',
'height' => '500'
), $atts, 'lottery_wheel');
if (!$atts['id']) {
return '<p>请指定抽奖活动ID</p>';
}
// 获取抽奖活动数据
global $wpdb;
$table_name = $wpdb->prefix . 'gamification_lotteries';
$lottery = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM $table_name WHERE id = %d AND status = 'active'",
$atts['id']
));
if (!$lottery) {
return '<p>抽奖活动不存在或已结束</p>';
}
// 获取奖品数据
$table_name_prizes = $wpdb->prefix . 'gamification_prizes';
$prizes = $wpdb->get_results($wpdb->prepare(
"SELECT * FROM $table_name_prizes WHERE lottery_id = %d ORDER BY id ASC",
$atts['id']
));
if (empty($prizes)) {
return '<p>抽奖活动暂无奖品</p>';
}
// 检查用户是否已参与
$user_id = get_current_user_id();
$table_name_participants = $wpdb->prefix . 'gamification_participants';
$has_participated = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $table_name_participants WHERE lottery_id = %d AND user_id = %d",
$atts['id'], $user_id
));
ob_start();
?>
<div class="lottery-container" data-lottery-id="<?php echo esc_attr($atts['id']); ?>">
<h3 class="lottery-title"><?php echo esc_html($lottery->title); ?></h3>
<div class="lottery-description"><?php echo wp_kses_post($lottery->description); ?></div>
<div class="lottery-wheel-container" style="width: <?php echo esc_attr($atts['width']); ?>px; height: <?php echo esc_attr($atts['height']); ?>px;">
<canvas id="lottery-wheel-<?php echo esc_attr($atts['id']); ?>" width="<?php echo esc_attr($atts['width']); ?>" height="<?php echo esc_attr($atts['height']); ?>"></canvas>
<div class="wheel-pointer"></div>
</div>
<div class="lottery-controls">
<?php if ($has_participated): ?>
<button class="lottery-button" disabled>您已参与过本次抽奖</button>
<?php else: ?>
<button class="lottery-button" id="spin-button-<?php echo esc_attr($atts['id']); ?>">开始抽奖</button>
<?php endif; ?>
</div>
<div class="lottery-prizes">
<h4>奖品列表</h4>
<ul>
<?php foreach ($prizes as $prize): ?>
<li>
<span class="prize-name"><?php echo esc_html($prize->name); ?></span>
<span class="prize-probability">中奖概率: <?php echo esc_html($prize->probability * 100); ?>%</span>
<span class="prize-remaining">剩余: <?php echo esc_html($prize->remaining); ?>份</span>
</li>
<?php endforeach; ?>
</ul>
</div>
</div>
<script type="text/javascript">
var lotteryData_<?php echo esc_attr($atts['id']); ?> = {
prizes: <?php echo json_encode($prizes); ?>,
lotteryId: <?php echo esc_attr($atts['id']); ?>,
userId: <?php echo $user_id ?: 0; ?>,
ajaxUrl: '<?php echo admin_url('admin-ajax.php'); ?>',
nonce: '<?php echo wp_create_nonce('lottery_spin_' . $atts['id']); ?>'
};
</script>
<?php
return ob_get_clean();
}
2.3 抽奖转盘Canvas绘制与动画
创建转盘的JavaScript绘制逻辑:
// assets/js/lottery-wheel.js
class LotteryWheel {
constructor(canvasId, options) {
this.canvas = document.getElementById(canvasId);
this.ctx = this.canvas.getContext('2d');
this.options = options;
this.prizes = options.prizes;
this.colors = ['#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF', '#FF9F40', '#FF6384', '#C9CBCF'];
this.isSpinning = false;
this.currentRotation = 0;
this.spinDuration = 4000; // 旋转持续时间(毫秒)
this.init();
}
init() {
this.drawWheel();
this.drawPointer();
}
drawWheel() {
const ctx = this.ctx;
const width = this.canvas.width;
const height = this.canvas.height;
const centerX = width / 2;
const centerY = height / 2;
const radius = Math.min(width, height) / 2 - 10;
// 清空画布
ctx.clearRect(0, 0, width, height);
// 绘制转盘背景
ctx.beginPath();
ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI);
ctx.fillStyle = '#f0f0f0';
ctx.fill();
ctx.strokeStyle = '#ddd';
ctx.lineWidth = 2;
ctx.stroke();
// 计算每个扇形的角度
const prizeCount = this.prizes.length;
const anglePerPrize = (2 * Math.PI) / prizeCount;
// 绘制每个扇形
for (let i = 0; i < prizeCount; i++) {
const startAngle = i * anglePerPrize + this.currentRotation;
const endAngle = (i + 1) * anglePerPrize + this.currentRotation;
// 绘制扇形
ctx.beginPath();
ctx.moveTo(centerX, centerY);
ctx.arc(centerX, centerY, radius, startAngle, endAngle);
ctx.closePath();
ctx.fillStyle = this.colors[i % this.colors.length];
ctx.fill();
ctx.strokeStyle = '#fff';
ctx.lineWidth = 1;
ctx.stroke();
// 绘制奖品文字
ctx.save();
ctx.translate(centerX, centerY);
ctx.rotate(startAngle + anglePerPrize / 2);
ctx.textAlign = 'right';
ctx.fillStyle = '#fff';
ctx.font = 'bold 14px Arial';
ctx.fillText(this.prizes[i].name, radius - 20, 5);
ctx.restore();
}
// 绘制中心圆
ctx.beginPath();
ctx.arc(centerX, centerY, 20, 0, 2 * Math.PI);
ctx.fillStyle = '#fff';
ctx.fill();
ctx.strokeStyle = '#ddd';
ctx.lineWidth = 3;
ctx.stroke();
}
drawPointer() {
const ctx = this.ctx;
const width = this.canvas.width;
const height = this.canvas.height;
const centerX = width / 2;
const centerY = height / 2;
// 绘制指针三角形
ctx.beginPath();
ctx.moveTo(centerX, 10);
ctx.lineTo(centerX - 15, 40);
ctx.lineTo(centerX + 15, 40);
ctx.closePath();
ctx.fillStyle = '#ff4444';
ctx.fill();
ctx.strokeStyle = '#cc0000';
ctx.lineWidth = 2;
ctx.stroke();
}
spin(prizeIndex, callback) {
if (this.isSpinning) return;
this.isSpinning = true;
// 计算目标旋转角度(确保旋转多圈后停在指定奖品)
const prizeCount = this.prizes.length;
const anglePerPrize = (2 * Math.PI) / prizeCount;
const targetPrizeAngle = prizeIndex * anglePerPrize;
// 计算总旋转角度(多转几圈)
const fullRotations = 5; // 完整旋转圈数
const targetRotation = fullRotations * 2 * Math.PI + targetPrizeAngle;
// 动画开始时间
const startTime = Date.now();
// 缓动函数
const easeOut = (t) => 1 - Math.pow(1 - t, 3);
// 动画函数
const animate = () => {
const currentTime = Date.now();
const elapsed = currentTime - startTime;
const progress = Math.min(elapsed / this.spinDuration, 1);
// 应用缓动函数
const easedProgress = easeOut(progress);
// 计算当前旋转角度
this.currentRotation = easedProgress * targetRotation;
// 重绘转盘
this.drawWheel();
this.drawPointer();
if (progress < 1) {
requestAnimationFrame(animate);
} else {
this.isSpinning = false;
if (callback) callback();
}
};
// 开始动画
animate();
}
}
第三章:AJAX交互与抽奖逻辑处理
3.1 抽奖逻辑与概率算法
// includes/class-lottery-engine.php
class Lottery_Engine {
public function process_spin($lottery_id, $user_id) {
global $wpdb;
// 验证抽奖活动
$lottery = $this->get_lottery($lottery_id);
if (!$lottery || $lottery->status !== 'active') {
return array('success' => false, 'message' => '抽奖活动不存在或已结束');
}
// 检查活动时间
$current_time = current_time('mysql');
if ($current_time < $lottery->start_date || $current_time > $lottery->end_date) {
return array('success' => false, 'message' => '抽奖活动未开始或已结束');
}
用户参与次数
$participation_count = $this->get_user_participation_count($lottery_id, $user_id);
$settings = maybe_unserialize($lottery->settings);
$max_participations = isset($settings['max_participations']) ? intval($settings['max_participations']) : 1;
if ($participation_count >= $max_participations) {
return array('success' => false, 'message' => '您已达到最大参与次数');
}
// 获取奖品列表
$prizes = $this->get_prizes($lottery_id);
if (empty($prizes)) {
return array('success' => false, 'message' => '抽奖活动暂无奖品');
}
// 执行抽奖算法
$winning_prize = $this->calculate_winner($prizes);
if (!$winning_prize) {
return array('success' => false, 'message' => '抽奖失败,请重试');
}
// 减少奖品库存
$this->decrease_prize_stock($winning_prize->id);
// 记录用户参与
$participation_id = $this->record_participation($lottery_id, $user_id, $winning_prize->id);
return array(
'success' => true,
'prize' => $winning_prize,
'participation_id' => $participation_id,
'message' => '恭喜您中奖了!'
);
}
private function calculate_winner($prizes) {
// 计算总概率
$total_probability = 0;
$available_prizes = array();
foreach ($prizes as $prize) {
if ($prize->remaining > 0) {
$total_probability += floatval($prize->probability);
$available_prizes[] = $prize;
}
}
if (empty($available_prizes)) {
return null;
}
// 如果总概率小于1,添加"未中奖"选项
if ($total_probability < 1) {
$no_prize = new stdClass();
$no_prize->id = 0;
$no_prize->name = '未中奖';
$no_prize->probability = 1 - $total_probability;
$available_prizes[] = $no_prize;
$total_probability = 1;
}
// 生成随机数
$random = mt_rand() / mt_getrandmax() * $total_probability;
// 确定中奖奖品
$cumulative_probability = 0;
foreach ($available_prizes as $prize) {
$cumulative_probability += floatval($prize->probability);
if ($random <= $cumulative_probability) {
return $prize->id == 0 ? null : $prize;
}
}
return null;
}
private function record_participation($lottery_id, $user_id, $prize_id) {
global $wpdb;
$table_name = $wpdb->prefix . 'gamification_participants';
$user_ip = $_SERVER['REMOTE_ADDR'];
$wpdb->insert(
$table_name,
array(
'user_id' => $user_id,
'lottery_id' => $lottery_id,
'prize_id' => $prize_id,
'win_status' => $prize_id ? 'won' : 'lost',
'ip_address' => $user_ip,
'created_at' => current_time('mysql')
),
array('%d', '%d', '%d', '%s', '%s', '%s')
);
return $wpdb->insert_id;
}
}
### 3.2 AJAX处理程序
// 添加AJAX处理
add_action('wp_ajax_gamification_spin_wheel', 'handle_spin_wheel_ajax');
add_action('wp_ajax_nopriv_gamification_spin_wheel', 'handle_spin_wheel_ajax');
function handle_spin_wheel_ajax() {
// 验证nonce
if (!check_ajax_referer('lottery_spin_' . $_POST['lottery_id'], 'nonce', false)) {
wp_die(json_encode(array(
'success' => false,
'message' => '安全验证失败'
)));
}
$lottery_id = intval($_POST['lottery_id']);
$user_id = get_current_user_id();
// 如果用户未登录,可以创建临时用户或使用IP限制
if (!$user_id) {
// 可以根据需要处理未登录用户
wp_die(json_encode(array(
'success' => false,
'message' => '请先登录'
)));
}
$engine = new Lottery_Engine();
$result = $engine->process_spin($lottery_id, $user_id);
wp_die(json_encode($result));
}
### 3.3 前端AJAX调用
// assets/js/lottery-frontend.js
jQuery(document).ready(function($) {
$('.lottery-button').on('click', function() {
var button = $(this);
var container = button.closest('.lottery-container');
var lotteryId = container.data('lottery-id');
var canvasId = 'lottery-wheel-' + lotteryId;
// 禁用按钮防止重复点击
button.prop('disabled', true).text('抽奖中...');
// 获取转盘实例
var wheel = window['lotteryWheel_' + lotteryId];
// 发送AJAX请求
$.ajax({
url: gamification_ajax.ajax_url,
type: 'POST',
data: {
action: 'gamification_spin_wheel',
lottery_id: lotteryId,
nonce: gamification_ajax.nonce
},
dataType: 'json',
success: function(response) {
if (response.success) {
// 计算奖品在转盘上的位置
var prizeIndex = 0;
if (response.prize) {
// 这里需要根据实际奖品列表计算索引
prizeIndex = calculatePrizeIndex(lotteryId, response.prize.id);
} else {
// 未中奖的位置
prizeIndex = Math.floor(Math.random() * 8); // 随机位置
}
// 开始转盘动画
wheel.spin(prizeIndex, function() {
// 动画完成后显示结果
showPrizeResult(response);
button.text('已参与');
});
} else {
alert(response.message);
button.prop('disabled', false).text('开始抽奖');
}
},
error: function() {
alert('网络错误,请重试');
button.prop('disabled', false).text('开始抽奖');
}
});
});
function calculatePrizeIndex(lotteryId, prizeId) {
// 根据lotteryData计算奖品索引
var lotteryData = window['lotteryData_' + lotteryId];
if (lotteryData && lotteryData.prizes) {
for (var i = 0; i < lotteryData.prizes.length; i++) {
if (lotteryData.prizes[i].id == prizeId) {
return i;
}
}
}
return 0;
}
function showPrizeResult(response) {
var message = response.message;
var prizeName = response.prize ? response.prize.name : '未中奖';
// 使用SweetAlert或自定义模态框显示结果
if (typeof Swal !== 'undefined') {
Swal.fire({
title: prizeName,
text: message,
icon: response.prize ? 'success' : 'info',
confirmButtonText: '确定'
});
} else {
// 简单的alert显示
alert(prizeName + ' - ' + message);
}
}
});
## 第四章:积分系统与用户进度追踪
### 4.1 积分系统数据库设计
// 扩展数据库表
function gamification_create_points_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
// 用户积分表
$table_name_points = $wpdb->prefix . 'gamification_user_points';
$sql = "CREATE TABLE IF NOT EXISTS $table_name_points (
id bigint(20) NOT NULL AUTO_INCREMENT,
user_id bigint(20) unsigned NOT NULL,
points int NOT NULL DEFAULT 0,
level int NOT NULL DEFAULT 1,
total_earned int NOT NULL DEFAULT 0,
last_updated datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE KEY user_id (user_id),
KEY points (points)
) $charset_collate;";
// 积分记录表
$table_name_points_log = $wpdb->prefix . 'gamification_points_log';
$sql2 = "CREATE TABLE IF NOT EXISTS $table_name_points_log (
id bigint(20) NOT NULL AUTO_INCREMENT,
user_id bigint(20) unsigned NOT NULL,
points_change int NOT NULL,
action_type varchar(100) NOT NULL,
action_id bigint(20),
description text,
created_at datetime DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
KEY user_id (user_id),
KEY action_type (action_type),
KEY created_at (created_at)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($sql);
dbDelta($sql2);
}
// 在插件激活时调用
register_activation_hook(__FILE__, 'gamification_create_points_tables');
### 4.2 积分管理类
// includes/class-points-manager.php
class Points_Manager {
public static function add_points($user_id, $points, $action_type, $action_id = null, $description = '') {
global $wpdb;
if (!$user_id || $points == 0) {
return false;
}
// 记录积分变更
$table_log = $wpdb->prefix . 'gamification_points_log';
$wpdb->insert(
$table_log,
array(
'user_id' => $user_id,
'points_change' => $points,
'action_type' => $action_type,
'action_id' => $action_id,
'description' => $description,
'created_at' => current_time('mysql')
),
array('%d', '%d', '%s', '%d', '%s', '%s')
);
// 更新用户总积分
$table_points = $wpdb->prefix . 'gamification_user_points';
// 检查用户是否已有积分记录
$existing = $wpdb->get_var($wpdb->prepare(
"SELECT id FROM $table_points WHERE user_id = %d",
$user_id
));
if ($existing) {
// 更新现有记录
$wpdb->query($wpdb->prepare(
"UPDATE $table_points SET
points = points + %d,
total_earned = total_earned + %d,
level = FLOOR(SQRT(total_earned + %d) / 10) + 1
WHERE user_id = %d",
$points, max($points, 0), max($points, 0), $user_id
));
} else {
// 创建新记录
$wpdb->insert(
$table_points,
array(
'user_id' => $user_id,
'points' => max($points, 0),
'total_earned' => max($points, 0),
'level' => 1,
'last_updated' => current_time('mysql')
),
array('%d', '%d', '%d', '%d', '%s')
);
}
// 检查是否达到升级条件
self::check_level_up($user_id);
return true;
}
public static function get_user_points($user_id) {
global $wpdb;
$table_points = $wpdb->prefix . 'gamification_user_points';
$result = $wpdb->get_row($wpdb->prepare(
"SELECT points, level, total_earned FROM $table_points WHERE user_id = %d",
$user_id
));
if (!$result) {
return array(
'points' => 0,
'level' => 1,
'total_earned' => 0
);
}
return array(
'points' => intval($result->points),
'level' => intval($result->level),
'total_earned' => intval($result->total_earned)
);
}
private static function check_level_up($user_id) {
$user_points = self::get_user_points($user_id);
$old_level = $user_points['level'];
// 计算新等级(每1000积分升一级)
$new_level = floor($user_points['total_earned'] / 1000) + 1;
if ($new_level > $old_level) {
// 触发等级提升事件
do_action('gamification_level_up', $user_id, $old_level, $new_level);
// 发送通知
self::send_level_up_notification($user_id, $old_level, $new_level);
}
}
private static function send_level_up_notification($user_id, $old_level, $new_level) {
$user = get_user_by('id', $user_id);
if (!$user) return;
$subject = sprintf('恭喜您升级到 %d 级!', $new_level);
$message = sprintf(
'亲爱的 %s,恭喜您从 %d 级升级到 %d 级!继续努力获取更多积分吧!',
$user->display_name,
$old_level,
$new_level
);
wp_mail($user->user_email, $subject, $message);
// 也可以添加站内通知
if (function_exists('bp_notifications_add_notification')) {
// BuddyPress 集成
bp_notifications_add_notification(array(
'user_id' => $user_id,
'item_id' => $new_level,
'component_name' => 'gamification',
'component_action' => 'level_up',
'date_notified' => bp_core_current_time(),
'is_new' => 1,
));
}
}
}
### 4.3 积分获取规则
// 定义积分获取规则
class Points_Rules {
private static $rules = array(
'daily_login' => array(
'points' => 10,
'limit' => 'daily',
'description' => '每日登录奖励'
),
'post_comment' => array(
'points' => 5,
'limit' => 'none',
'description' => '发表评论'
),
'lottery_participation' => array(
'points' => 2,
'limit' => 'daily',
'description' => '参与抽奖'
),
'lottery_win' => array(
'points' => 20,
'limit' => 'none',
'description' => '抽奖中奖'
),
'share_content' => array(
'points' => 15,
'limit' => 'daily',
'description' => '分享内容'
),
'complete_profile' => array(
'points' => 50,
'limit' => 'once',
'description' => '完善个人资料'
)
);
public static function apply_rule($user_id, $rule_name, $action_id = null) {
if (!isset(self::$rules[$rule_name])) {
return false;
}
$rule = self::$rules[$rule_name];
// 检查限制条件
if (!self::check_limit($user_id, $rule_name, $rule['limit'])) {
return false;
}
// 添加积分
Points_Manager::add_points(
$user_id,
$rule['points'],
$rule_name,
$action_id,
$rule['description']
);
return true;
}
private static function check_limit($user_id, $rule_name, $limit_type) {
global $wpdb;
$table_log = $wpdb->prefix . 'gamification_points_log';
switch ($limit_type) {
case 'daily':
// 检查今天是否已经获得过
$today = date('Y-m-d');
$count = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $table_log
WHERE user_id = %d
AND action_type = %s
AND DATE(created_at) = %s",
$user_id, $rule_name, $today
));
return $count == 0;
case 'once':
// 检查是否已经获得过
$count = $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $table_log
WHERE user_id = %d
AND action_type = %s",
$user_id, $rule_name
));
return $count == 0;
case 'none':
default:
return true;
}
}
}
## 第五章:进度条与成就系统
### 5.1 进度条组件
// 进度条短代码
add_shortcode('progress_bar', 'gamification_progress_bar_shortcode');
function gamification_progress_bar_shortcode($atts) {
$atts = shortcode_atts(array(
'type' => 'points', // points, level, custom
'target' => 1000,
'current' => '',
'height' => '20
