文章目录[隐藏]
WordPress文创项目柔性众筹插件开发详解
一、项目背景与需求分析
随着文创产业的蓬勃发展,越来越多的创作者需要灵活的资金支持方式。传统的众筹平台往往采用"全有或全无"的固定模式,缺乏灵活性。为此,我们开发了一款WordPress柔性众筹插件,允许创作者设置弹性目标,按实际筹集金额比例交付回报。
核心需求:
- 支持弹性目标设置(最低目标、理想目标、超额目标)
- 多种支付方式集成(支付宝、微信支付、银行卡)
- 多级回报体系
- 实时进度展示
- 后台管理界面
- 数据统计与分析
二、插件架构设计
2.1 数据库设计
<?php
/**
* 创建插件所需数据表
* 在插件激活时执行
*/
function flexible_crowdfunding_create_tables() {
global $wpdb;
$charset_collate = $wpdb->get_charset_collate();
$table_prefix = $wpdb->prefix . 'fc_';
// 项目表
$projects_table = $table_prefix . 'projects';
$projects_sql = "CREATE TABLE IF NOT EXISTS $projects_table (
id INT(11) NOT NULL AUTO_INCREMENT,
post_id INT(11) NOT NULL,
creator_id INT(11) NOT NULL,
title VARCHAR(255) NOT NULL,
description TEXT,
min_target DECIMAL(10,2) DEFAULT 0.00,
ideal_target DECIMAL(10,2) DEFAULT 0.00,
stretch_target DECIMAL(10,2) DEFAULT 0.00,
current_amount DECIMAL(10,2) DEFAULT 0.00,
start_date DATETIME,
end_date DATETIME,
status ENUM('draft', 'active', 'completed', 'failed') DEFAULT 'draft',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
INDEX idx_post_id (post_id),
INDEX idx_status (status)
) $charset_collate;";
// 支持记录表
$backers_table = $table_prefix . 'backers';
$backers_sql = "CREATE TABLE IF NOT EXISTS $backers_table (
id INT(11) NOT NULL AUTO_INCREMENT,
project_id INT(11) NOT NULL,
user_id INT(11),
anonymous_name VARCHAR(100),
amount DECIMAL(10,2) NOT NULL,
reward_id INT(11),
payment_method VARCHAR(50),
transaction_id VARCHAR(100),
status ENUM('pending', 'completed', 'refunded') DEFAULT 'pending',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
INDEX idx_project_id (project_id),
INDEX idx_user_id (user_id),
INDEX idx_status (status)
) $charset_collate;";
// 回报等级表
$rewards_table = $table_prefix . 'rewards';
$rewards_sql = "CREATE TABLE IF NOT EXISTS $rewards_table (
id INT(11) NOT NULL AUTO_INCREMENT,
project_id INT(11) NOT NULL,
title VARCHAR(255) NOT NULL,
description TEXT,
amount DECIMAL(10,2) NOT NULL,
limit_count INT(11) DEFAULT 0,
claimed_count INT(11) DEFAULT 0,
delivery_date DATE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (id),
INDEX idx_project_id (project_id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
dbDelta($projects_sql);
dbDelta($backers_sql);
dbDelta($rewards_sql);
}
register_activation_hook(__FILE__, 'flexible_crowdfunding_create_tables');
?>
2.2 插件主类结构
<?php
/**
* 柔性众筹插件主类
*/
class Flexible_Crowdfunding_Plugin {
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();
}
/**
* 初始化WordPress钩子
*/
private function init_hooks() {
// 注册自定义文章类型
add_action('init', array($this, 'register_crowdfunding_post_type'));
// 添加管理菜单
add_action('admin_menu', array($this, 'add_admin_menu'));
// 注册短代码
add_shortcode('crowdfunding_project', array($this, 'render_project_shortcode'));
// 注册AJAX处理
add_action('wp_ajax_support_project', array($this, 'handle_support_ajax'));
add_action('wp_ajax_nopriv_support_project', array($this, 'handle_support_ajax'));
// 添加CSS和JS
add_action('wp_enqueue_scripts', array($this, 'enqueue_frontend_assets'));
add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_assets'));
}
/**
* 注册众筹项目自定义文章类型
*/
public function register_crowdfunding_post_type() {
$labels = array(
'name' => '众筹项目',
'singular_name' => '众筹项目',
'menu_name' => '文创众筹',
'add_new' => '添加项目',
'add_new_item' => '添加新项目',
'edit_item' => '编辑项目',
'new_item' => '新项目',
'view_item' => '查看项目',
'search_items' => '搜索项目',
'not_found' => '未找到项目',
'not_found_in_trash' => '回收站中无项目'
);
$args = array(
'labels' => $labels,
'public' => true,
'publicly_queryable'=> true,
'show_ui' => true,
'show_in_menu' => true,
'query_var' => true,
'rewrite' => array('slug' => 'crowdfunding'),
'capability_type' => 'post',
'has_archive' => true,
'hierarchical' => false,
'menu_position' => 5,
'menu_icon' => 'dashicons-heart',
'supports' => array('title', 'editor', 'thumbnail', 'excerpt', 'comments'),
'show_in_rest' => true
);
register_post_type('crowdfunding_project', $args);
}
// 其他方法将在后续章节实现
}
?>
三、前端展示模块开发
3.1 项目展示短代码
<?php
/**
* 渲染众筹项目短代码
* @param array $atts 短代码属性
* @return string HTML内容
*/
public function render_project_shortcode($atts) {
// 解析短代码属性
$atts = shortcode_atts(array(
'id' => 0,
'show_progress' => true,
'show_backers' => true,
'show_rewards' => true
), $atts, 'crowdfunding_project');
// 获取项目数据
$project_id = intval($atts['id']);
if ($project_id <= 0) {
return '<div class="fc-error">无效的项目ID</div>';
}
global $wpdb;
$table_name = $wpdb->prefix . 'fc_projects';
$project = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM $table_name WHERE post_id = %d",
$project_id
));
if (!$project) {
return '<div class="fc-error">项目不存在</div>';
}
// 计算进度百分比
$progress_percentage = 0;
if ($project->ideal_target > 0) {
$progress_percentage = min(100, ($project->current_amount / $project->ideal_target) * 100);
}
// 计算剩余天数
$days_left = 0;
if ($project->end_date) {
$end_date = new DateTime($project->end_date);
$now = new DateTime();
if ($end_date > $now) {
$days_left = $end_date->diff($now)->days;
}
}
ob_start();
?>
<div class="fc-project-container" data-project-id="<?php echo esc_attr($project_id); ?>">
<!-- 项目标题和描述 -->
<div class="fc-project-header">
<h2 class="fc-project-title"><?php echo esc_html($project->title); ?></h2>
<div class="fc-project-description">
<?php echo wp_kses_post($project->description); ?>
</div>
</div>
<!-- 进度条 -->
<?php if ($atts['show_progress']): ?>
<div class="fc-progress-section">
<div class="fc-progress-stats">
<div class="fc-amount-raised">
<span class="fc-label">已筹集</span>
<span class="fc-value">¥<?php echo number_format($project->current_amount, 2); ?></span>
</div>
<div class="fc-target-amount">
<span class="fc-label">目标金额</span>
<span class="fc-value">¥<?php echo number_format($project->ideal_target, 2); ?></span>
</div>
<div class="fc-backers-count">
<span class="fc-label">支持者</span>
<span class="fc-value"><?php echo $this->get_backers_count($project->id); ?></span>
</div>
<div class="fc-days-left">
<span class="fc-label">剩余时间</span>
<span class="fc-value"><?php echo $days_left; ?>天</span>
</div>
</div>
<div class="fc-progress-bar-container">
<div class="fc-progress-bar">
<div class="fc-progress-fill" style="width: <?php echo esc_attr($progress_percentage); ?>%;"></div>
</div>
<div class="fc-progress-labels">
<span>¥<?php echo number_format($project->min_target, 2); ?> (最低)</span>
<span>¥<?php echo number_format($project->ideal_target, 2); ?> (理想)</span>
<?php if ($project->stretch_target > 0): ?>
<span>¥<?php echo number_format($project->stretch_target, 2); ?> (超额)</span>
<?php endif; ?>
</div>
</div>
</div>
<?php endif; ?>
<!-- 支持按钮 -->
<div class="fc-support-section">
<button class="fc-support-button" data-action="open-support-modal">
支持这个项目
</button>
</div>
<!-- 回报等级 -->
<?php if ($atts['show_rewards']):
$rewards = $this->get_project_rewards($project->id);
if ($rewards):
?>
<div class="fc-rewards-section">
<h3>选择回报</h3>
<div class="fc-rewards-grid">
<?php foreach ($rewards as $reward):
$claimed_percentage = 0;
if ($reward->limit_count > 0) {
$claimed_percentage = ($reward->claimed_count / $reward->limit_count) * 100;
}
?>
<div class="fc-reward-card" data-reward-id="<?php echo esc_attr($reward->id); ?>">
<div class="fc-reward-header">
<h4 class="fc-reward-title"><?php echo esc_html($reward->title); ?></h4>
<div class="fc-reward-amount">¥<?php echo number_format($reward->amount, 2); ?></div>
</div>
<div class="fc-reward-description">
<?php echo wp_kses_post($reward->description); ?>
</div>
<?php if ($reward->limit_count > 0): ?>
<div class="fc-reward-limit">
<div class="fc-limit-progress">
<div class="fc-limit-progress-bar" style="width: <?php echo esc_attr($claimed_percentage); ?>%;"></div>
</div>
<div class="fc-limit-text">
已领取 <?php echo esc_html($reward->claimed_count); ?> / <?php echo esc_html($reward->limit_count); ?>
</div>
</div>
<?php endif; ?>
<button class="fc-select-reward" data-reward-id="<?php echo esc_attr($reward->id); ?>">
选择此回报
</button>
</div>
<?php endforeach; ?>
</div>
</div>
<?php endif; endif; ?>
</div>
<!-- 支持模态框 -->
<div class="fc-modal" id="fc-support-modal">
<div class="fc-modal-content">
<span class="fc-modal-close">×</span>
<h3>支持项目</h3>
<form id="fc-support-form">
<input type="hidden" name="project_id" value="<?php echo esc_attr($project->id); ?>">
<input type="hidden" name="reward_id" id="fc-selected-reward" value="0">
<div class="fc-form-group">
<label for="fc-support-amount">支持金额 (元)</label>
<input type="number" id="fc-support-amount" name="amount" min="1" step="0.01" required>
</div>
<div class="fc-form-group">
<label for="fc-payment-method">支付方式</label>
<select id="fc-payment-method" name="payment_method" required>
<option value="">请选择支付方式</option>
<option value="alipay">支付宝</option>
<option value="wechat">微信支付</option>
<option value="bank">银行卡</option>
</select>
</div>
<div class="fc-form-group">
<label>
<input type="checkbox" name="anonymous" value="1">
匿名支持
</label>
</div>
<div class="fc-form-group" id="fc-anonymous-name-group" style="display: none;">
<label for="fc-anonymous-name">显示名称</label>
<input type="text" id="fc-anonymous-name" name="anonymous_name" placeholder="请输入显示名称">
</div>
<button type="submit" class="fc-submit-button">确认支持</button>
</form>
</div>
</div>
<?php
return ob_get_clean();
}
/**
* 获取项目支持者数量
*/
private function get_backers_count($project_id) {
global $wpdb;
$table_name = $wpdb->prefix . 'fc_backers';
return $wpdb->get_var($wpdb->prepare(
"SELECT COUNT(*) FROM $table_name WHERE project_id = %d AND status = 'completed'",
$project_id
));
}
/**
* 获取项目回报等级
*/
private function get_project_rewards($project_id) {
global $wpdb;
$table_name = $wpdb->prefix . 'fc_rewards';
return $wpdb->get_results($wpdb->prepare(
"SELECT * FROM $table_name WHERE project_id = %d ORDER BY amount ASC",
$project_id
));
}
?>
3.2 前端样式与交互
/* 柔性众筹插件前端样式 */
.fc-project-container {
max-width: 1200px;
margin: 0 auto;
padding: 20px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
}
.fc-project-header {
margin-bottom: 30px;
}
.fc-project-title {
font-size: 2.5rem;
color: #333;
margin-bottom: 15px;
}
.fc-project-description {
font-size: 1.1rem;
line-height: 1.6;
color: #666;
}
.fc-progress-section {
background: #f8f9fa;
border-radius: 10px;
padding: 25px;
margin-bottom: 30px;
box-shadow: 0 2px 10px rgba(0,0,0,0.05);
}
.fc-progress-stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 20px;
margin-bottom: 25px;
}
.fc-progress-stats > div {
text-align: center;
}
.fc-label {
display: block;
font-size: 0.9rem;
color: #666;
margin-bottom: 5px;
}
.fc-value {
display: block;
font-size: 1.8rem;
font-weight: bold;
color: #2c3e50;
}
.fc-progress-bar-container {
margin-top: 20px;
}
.fc-progress-bar {
height: 20px;
background: #e9ecef;
border-radius: 10px;
overflow: hidden;
position: relative;
}
.fc-progress-fill {
height: 100%;
background: linear-gradient(90deg, #3498db, #2ecc71);
border-radius: 10px;
transition: width 1s ease-in-out;
}
.fc-progress-labels {
display: flex;
justify-content: space-between;
margin-top: 10px;
font-size: 0.9rem;
color: #666;
}
.fc-support-section {
.fc-support-button {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
border: none;
padding: 15px 40px;
font-size: 1.2rem;
border-radius: 50px;
cursor: pointer;
transition: all 0.3s ease;
display: block;
margin: 30px auto;
box-shadow: 0 4px 15px rgba(102, 126, 234, 0.3);
}
.fc-support-button:hover {
transform: translateY(-2px);
box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
}
.fc-rewards-section {
margin-top: 40px;
}
.fc-rewards-section h3 {
font-size: 1.8rem;
color: #333;
margin-bottom: 25px;
text-align: center;
}
.fc-rewards-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 25px;
margin-top: 20px;
}
.fc-reward-card {
border: 2px solid #e9ecef;
border-radius: 12px;
padding: 25px;
transition: all 0.3s ease;
position: relative;
overflow: hidden;
}
.fc-reward-card:hover {
border-color: #3498db;
box-shadow: 0 10px 30px rgba(52, 152, 219, 0.1);
transform: translateY(-5px);
}
.fc-reward-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 15px;
}
.fc-reward-title {
font-size: 1.3rem;
color: #2c3e50;
margin: 0;
flex: 1;
}
.fc-reward-amount {
font-size: 1.5rem;
font-weight: bold;
color: #e74c3c;
margin-left: 15px;
}
.fc-reward-description {
color: #666;
line-height: 1.6;
margin-bottom: 20px;
min-height: 80px;
}
.fc-reward-limit {
margin-bottom: 20px;
}
.fc-limit-progress {
height: 8px;
background: #f1f1f1;
border-radius: 4px;
overflow: hidden;
margin-bottom: 8px;
}
.fc-limit-progress-bar {
height: 100%;
background: linear-gradient(90deg, #f39c12, #e67e22);
transition: width 0.5s ease;
}
.fc-limit-text {
font-size: 0.9rem;
color: #7f8c8d;
text-align: center;
}
.fc-select-reward {
background: #2ecc71;
color: white;
border: none;
padding: 12px 25px;
border-radius: 6px;
cursor: pointer;
width: 100%;
font-size: 1rem;
transition: all 0.3s ease;
}
.fc-select-reward:hover {
background: #27ae60;
transform: scale(1.02);
}
/* 模态框样式 */
.fc-modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
.fc-modal-content {
background-color: white;
margin: 5% auto;
padding: 30px;
border-radius: 15px;
width: 90%;
max-width: 500px;
position: relative;
animation: slideIn 0.3s ease;
}
@keyframes slideIn {
from { transform: translateY(-50px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
.fc-modal-close {
position: absolute;
right: 20px;
top: 15px;
font-size: 28px;
cursor: pointer;
color: #95a5a6;
transition: color 0.3s;
}
.fc-modal-close:hover {
color: #e74c3c;
}
.fc-modal-content h3 {
color: #2c3e50;
margin-bottom: 25px;
text-align: center;
}
.fc-form-group {
margin-bottom: 20px;
}
.fc-form-group label {
display: block;
margin-bottom: 8px;
color: #34495e;
font-weight: 500;
}
.fc-form-group input[type="number"],
.fc-form-group input[type="text"],
.fc-form-group select {
width: 100%;
padding: 12px 15px;
border: 2px solid #ddd;
border-radius: 8px;
font-size: 1rem;
transition: border-color 0.3s;
}
.fc-form-group input:focus,
.fc-form-group select:focus {
outline: none;
border-color: #3498db;
}
.fc-submit-button {
background: linear-gradient(135deg, #3498db, #2980b9);
color: white;
border: none;
padding: 15px 30px;
font-size: 1.1rem;
border-radius: 8px;
cursor: pointer;
width: 100%;
transition: all 0.3s ease;
margin-top: 10px;
}
.fc-submit-button:hover {
background: linear-gradient(135deg, #2980b9, #1c5a7a);
transform: translateY(-2px);
}
/* 响应式设计 */
@media (max-width: 768px) {
.fc-progress-stats {
grid-template-columns: repeat(2, 1fr);
}
.fc-rewards-grid {
grid-template-columns: 1fr;
}
.fc-project-title {
font-size: 2rem;
}
.fc-modal-content {
margin: 10% auto;
width: 95%;
}
}
// 前端交互脚本
jQuery(document).ready(function($) {
'use strict';
// 支持按钮点击事件
$(document).on('click', '.fc-support-button', function() {
$('#fc-support-modal').fadeIn(300);
$('body').css('overflow', 'hidden');
});
// 关闭模态框
$(document).on('click', '.fc-modal-close, .fc-modal', function(e) {
if ($(e.target).hasClass('fc-modal') || $(e.target).hasClass('fc-modal-close')) {
$('#fc-support-modal').fadeOut(300);
$('body').css('overflow', 'auto');
}
});
// 选择回报
$(document).on('click', '.fc-select-reward', function(e) {
e.preventDefault();
const rewardId = $(this).data('reward-id');
const rewardAmount = $(this).closest('.fc-reward-card').find('.fc-reward-amount').text();
// 设置选中的回报
$('#fc-selected-reward').val(rewardId);
$('#fc-support-amount').val(rewardAmount.replace('¥', '').trim());
// 显示模态框
$('#fc-support-modal').fadeIn(300);
$('body').css('overflow', 'hidden');
// 添加选中效果
$('.fc-reward-card').removeClass('fc-reward-selected');
$(this).closest('.fc-reward-card').addClass('fc-reward-selected');
});
// 匿名支持复选框
$('input[name="anonymous"]').on('change', function() {
if ($(this).is(':checked')) {
$('#fc-anonymous-name-group').slideDown(300);
$('#fc-anonymous-name').prop('required', true);
} else {
$('#fc-anonymous-name-group').slideUp(300);
$('#fc-anonymous-name').prop('required', false);
}
});
// 提交支持表单
$('#fc-support-form').on('submit', function(e) {
e.preventDefault();
const formData = $(this).serialize();
const submitButton = $(this).find('.fc-submit-button');
const originalText = submitButton.text();
// 显示加载状态
submitButton.prop('disabled', true).text('处理中...');
// AJAX请求
$.ajax({
url: fc_ajax.ajax_url,
type: 'POST',
data: {
action: 'support_project',
nonce: fc_ajax.nonce,
form_data: formData
},
success: function(response) {
if (response.success) {
// 成功处理
submitButton.text('支持成功!');
submitButton.css('background', '#2ecc71');
// 更新页面数据
updateProjectStats(response.data.project_id);
// 3秒后关闭模态框
setTimeout(function() {
$('#fc-support-modal').fadeOut(300);
$('body').css('overflow', 'auto');
submitButton.prop('disabled', false).text(originalText).css('background', '');
}, 3000);
} else {
// 错误处理
alert(response.data.message || '操作失败,请重试');
submitButton.prop('disabled', false).text(originalText);
}
},
error: function() {
alert('网络错误,请检查连接后重试');
submitButton.prop('disabled', false).text(originalText);
}
});
});
// 更新项目统计数据
function updateProjectStats(projectId) {
$.ajax({
url: fc_ajax.ajax_url,
type: 'POST',
data: {
action: 'get_project_stats',
project_id: projectId,
nonce: fc_ajax.nonce
},
success: function(response) {
if (response.success) {
const data = response.data;
// 更新金额
$('.fc-amount-raised .fc-value').text('¥' + data.current_amount);
// 更新支持者数量
$('.fc-backers-count .fc-value').text(data.backers_count);
// 更新进度条
const percentage = Math.min(100, (data.current_amount / data.ideal_target) * 100);
$('.fc-progress-fill').css('width', percentage + '%');
// 更新回报领取数量
if (data.rewards) {
data.rewards.forEach(function(reward) {
const $rewardCard = $('.fc-reward-card[data-reward-id="' + reward.id + '"]');
if ($rewardCard.length) {
$rewardCard.find('.fc-limit-text').text(
'已领取 ' + reward.claimed_count + ' / ' + reward.limit_count
);
const claimedPercentage = (reward.claimed_count / reward.limit_count) * 100;
$rewardCard.find('.fc-limit-progress-bar').css('width', claimedPercentage + '%');
}
});
}
}
}
});
}
// 实时倒计时
function updateCountdown() {
$('.fc-days-left .fc-value').each(function() {
const days = parseInt($(this).text());
if (days > 0) {
$(this).text((days - 1) + '天');
} else if (days === 0) {
$(this).text('已结束');
$(this).css('color', '#e74c3c');
}
});
}
// 每小时更新一次倒计时
setInterval(updateCountdown, 3600000);
});
四、支付处理模块
<?php
/**
* 支付处理类
*/
class FC_Payment_Handler {
/**
* 处理支付请求
*/
public function process_payment($data) {
// 验证数据
$validation = $this->validate_payment_data($data);
if (!$validation['valid']) {
return array(
'success' => false,
'message' => $validation['message']
);
}
// 根据支付方式选择处理器
switch ($data['payment_method']) {
case 'alipay':
return $this->process_alipay($data);
case 'wechat':
return $this->process_wechat_pay($data);
case 'bank':
return $this->process_bank_transfer($data);
default:
return array(
'success' => false,
'message' => '不支持的支付方式'
);
}
}
/**
* 验证支付数据
*/
private function validate_payment_data($data) {
// 检查必填字段
$required_fields = array('project_id', 'amount', 'payment_method');
foreach ($required_fields as $field) {
if (empty($data[$field])) {
return array(
'valid' => false,
'message' => '缺少必要字段: ' . $field
);
}
}
// 验证金额
$amount = floatval($data['amount']);
if ($amount <= 0) {
return array(
'valid' => false,
'message' => '金额必须大于0'
);
}
// 验证项目是否存在
global $wpdb;
$projects_table = $wpdb->prefix . 'fc_projects';
$project = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM $projects_table WHERE id = %d AND status = 'active'",
intval($data['project_id'])
));
if (!$project) {
return array(
'valid' => false,
'message' => '项目不存在或未激活'
);
}
// 验证回报(如果选择了回报)
if (!empty($data['reward_id'])) {
$rewards_table = $wpdb->prefix . 'fc_rewards';
$reward = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM $rewards_table WHERE id = %d AND project_id = %d",
intval($data['reward_id']),
intval($data['project_id'])
));
if (!$reward) {
return array(
'valid' => false,
'message' => '选择的回报不存在'
);
}
// 检查回报是否已领完
if ($reward->limit_count > 0 && $reward->claimed_count >= $reward->limit_count) {
return array(
'valid' => false,
'message' => '该回报已领完'
);
}
// 检查金额是否达到回报要求
if ($amount < $reward->amount) {
return array(
'valid' => false,
'message' => '金额未达到该回报要求'
);
}
}
return array('valid' => true);
}
/**
* 处理支付宝支付
*/
private function process_alipay($data) {
// 这里应该集成支付宝SDK
// 以下为示例代码
$order_id = $this->generate_order_id();
// 创建本地订单记录
$backer_id = $this->create_backer_record(array_merge($data, array(
'order_id' => $order_id,
'status' => 'pending'
)));
if (!$backer_id) {
return array(
'success' => false,
'message' => '创建订单失败'
);
}
// 实际项目中这里应该调用支付宝API
// $alipay_result = $this->call_alipay_api($order_id, $data['amount']);
// 模拟支付成功
$payment_result = array(
'success' => true,
'trade_no' => 'ALIPAY' . time() . rand(1000, 9999),
'payment_url' => '#', // 实际项目中返回支付页面URL
'order_id' => $order_id
);
if ($payment_result['success']) {
// 更新订单状态
$this->update_backer_status($backer_id, 'completed', array(
'transaction_id' => $payment_result['trade_no']
));
// 更新项目金额
$this->update_project_amount($data['project_id'], $data['amount']);
// 更新回报领取数量
if (!empty($data['reward_id'])) {
$this->update_reward_claimed_count($data['reward_id']);
}
return array(
'success' => true,
'data' => array(
'order_id' => $order_id,
'payment_url' => $payment_result['payment_url']
)
);
}
return array(
'success' => false,
'message' => '支付处理失败'
);
}
/**
* 生成订单ID
*/
private function generate_order_id() {
return date('YmdHis') . str_pad(mt_rand(1, 99999), 5, '0', STR_PAD_LEFT);
}
/**
* 创建支持者记录
*/
private function create_backer_record($data) {
global $wpdb;
$user_id = get_current_user_id();
$anonymous = isset($data['anonymous']) && $data['anonymous'] == 1;
$backer_data = array(
'project_id' => intval($data['project_id']),
