首页 / 应用软件 / 详细教程,为WordPress网站开发活动抽奖与互动游戏化组件

详细教程,为WordPress网站开发活动抽奖与互动游戏化组件

WordPress网站活动抽奖与互动游戏化组件开发详细教程

引言:为什么WordPress网站需要游戏化组件

在当今互联网环境中,用户参与度和互动性已成为网站成功的关键指标。无论是电商平台、内容网站还是企业官网,通过游戏化元素如抽奖、积分系统、进度条等互动组件,可以显著提升用户粘性、延长停留时间并促进转化。WordPress作为全球最流行的内容管理系统,拥有强大的扩展能力,通过代码二次开发,我们可以为网站添加各种互联网常用的小工具功能。

本教程将详细指导您如何为WordPress网站开发活动抽奖与互动游戏化组件,从环境搭建到功能实现,涵盖完整的技术流程。无论您是WordPress开发者还是有一定技术基础的网站管理员,都能通过本教程掌握相关技能。

第一章:开发环境准备与基础架构

1.1 开发环境配置

在开始开发之前,我们需要准备合适的开发环境:

  1. 本地开发环境:推荐使用XAMPP、MAMP或Local by Flywheel
  2. WordPress安装:最新版本的WordPress(建议5.8+)
  3. 代码编辑器:VS Code、Sublime Text或PHPStorm
  4. 浏览器开发者工具: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
本文来自网络,不代表柔性供应链服务中心立场,转载请注明出处:https://mall.org.cn/5164.html

EXCHANGES®作者

上一篇
下一篇

为您推荐

发表回复

联系我们

联系我们

18559313275

在线咨询: QQ交谈

邮箱: vip@exchanges.center

工作时间:周一至周五,9:00-17:30,节假日休息
返回顶部