363 lines
11 KiB
PHP
363 lines
11 KiB
PHP
<?php
|
||
/**
|
||
* 计划任务类
|
||
*
|
||
* @package YooneSubscriptions
|
||
*/
|
||
|
||
if (!defined('ABSPATH')) {
|
||
exit;
|
||
}
|
||
|
||
/**
|
||
* Yoone_Cron类
|
||
* 处理计划任务
|
||
*/
|
||
class Yoone_Cron {
|
||
|
||
/**
|
||
* 构造函数
|
||
*/
|
||
public function __construct() {
|
||
$this->init_hooks();
|
||
$this->schedule_events();
|
||
}
|
||
|
||
/**
|
||
* 初始化钩子
|
||
*/
|
||
private function init_hooks() {
|
||
// 订阅续费处理
|
||
add_action('yoone_process_subscription_renewals', array($this, 'process_subscription_renewals'));
|
||
|
||
// 清理过期令牌
|
||
add_action('yoone_cleanup_expired_tokens', array($this, 'cleanup_expired_tokens'));
|
||
|
||
// 清理过期订阅
|
||
add_action('yoone_cleanup_expired_subscriptions', array($this, 'cleanup_expired_subscriptions'));
|
||
|
||
// 发送订阅提醒邮件
|
||
add_action('yoone_send_subscription_reminders', array($this, 'send_subscription_reminders'));
|
||
|
||
// 清理日志文件
|
||
add_action('yoone_cleanup_logs', array($this, 'cleanup_logs'));
|
||
|
||
// 添加自定义计划间隔
|
||
add_filter('cron_schedules', array($this, 'add_cron_schedules'));
|
||
}
|
||
|
||
/**
|
||
* 安排计划事件
|
||
*/
|
||
private function schedule_events() {
|
||
// 每小时处理订阅续费
|
||
if (!wp_next_scheduled('yoone_process_subscription_renewals')) {
|
||
wp_schedule_event(time(), 'hourly', 'yoone_process_subscription_renewals');
|
||
}
|
||
|
||
// 每天清理过期令牌
|
||
if (!wp_next_scheduled('yoone_cleanup_expired_tokens')) {
|
||
wp_schedule_event(time(), 'daily', 'yoone_cleanup_expired_tokens');
|
||
}
|
||
|
||
// 每天清理过期订阅
|
||
if (!wp_next_scheduled('yoone_cleanup_expired_subscriptions')) {
|
||
wp_schedule_event(time(), 'daily', 'yoone_cleanup_expired_subscriptions');
|
||
}
|
||
|
||
// 每天发送订阅提醒邮件
|
||
if (!wp_next_scheduled('yoone_send_subscription_reminders')) {
|
||
wp_schedule_event(time(), 'daily', 'yoone_send_subscription_reminders');
|
||
}
|
||
|
||
// 每周清理日志文件
|
||
if (!wp_next_scheduled('yoone_cleanup_logs')) {
|
||
wp_schedule_event(time(), 'weekly', 'yoone_cleanup_logs');
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 添加自定义计划间隔
|
||
*
|
||
* @param array $schedules 现有计划
|
||
* @return array 更新后的计划
|
||
*/
|
||
public function add_cron_schedules($schedules) {
|
||
// 每15分钟
|
||
$schedules['fifteen_minutes'] = array(
|
||
'interval' => 15 * 60,
|
||
'display' => __('每15分钟', 'yoone-subscriptions')
|
||
);
|
||
|
||
// 每30分钟
|
||
$schedules['thirty_minutes'] = array(
|
||
'interval' => 30 * 60,
|
||
'display' => __('每30分钟', 'yoone-subscriptions')
|
||
);
|
||
|
||
return $schedules;
|
||
}
|
||
|
||
/**
|
||
* 处理订阅续费
|
||
*/
|
||
public function process_subscription_renewals() {
|
||
Yoone_Logger::info('开始处理订阅续费');
|
||
|
||
global $wpdb;
|
||
|
||
// 获取需要续费的订阅
|
||
$subscriptions = $wpdb->get_results($wpdb->prepare("
|
||
SELECT * FROM {$wpdb->prefix}yoone_subscriptions
|
||
WHERE status = 'active'
|
||
AND next_payment_date <= %s
|
||
AND next_payment_date IS NOT NULL
|
||
LIMIT 50
|
||
", current_time('mysql')));
|
||
|
||
$processed = 0;
|
||
$failed = 0;
|
||
|
||
foreach ($subscriptions as $subscription_data) {
|
||
try {
|
||
$subscription = new Yoone_Subscription($subscription_data->id);
|
||
|
||
if ($subscription->process_renewal()) {
|
||
$processed++;
|
||
Yoone_Logger::log_subscription($subscription->get_id(), '订阅续费成功');
|
||
} else {
|
||
$failed++;
|
||
Yoone_Logger::log_subscription($subscription->get_id(), '订阅续费失败', Yoone_Logger::ERROR);
|
||
}
|
||
} catch (Exception $e) {
|
||
$failed++;
|
||
Yoone_Logger::error('订阅续费异常: ' . $e->getMessage(), array(
|
||
'subscription_id' => $subscription_data->id
|
||
));
|
||
}
|
||
}
|
||
|
||
Yoone_Logger::info("订阅续费处理完成: 成功 {$processed}, 失败 {$failed}");
|
||
}
|
||
|
||
/**
|
||
* 清理过期令牌
|
||
*/
|
||
public function cleanup_expired_tokens() {
|
||
Yoone_Logger::info('开始清理过期支付令牌');
|
||
|
||
global $wpdb;
|
||
|
||
$deleted = $wpdb->query($wpdb->prepare("
|
||
DELETE FROM {$wpdb->prefix}yoone_payment_tokens
|
||
WHERE expires_at < %s
|
||
", current_time('mysql')));
|
||
|
||
Yoone_Logger::info("清理过期令牌完成: 删除 {$deleted} 个令牌");
|
||
}
|
||
|
||
/**
|
||
* 清理过期订阅
|
||
*/
|
||
public function cleanup_expired_subscriptions() {
|
||
Yoone_Logger::info('开始清理过期订阅');
|
||
|
||
global $wpdb;
|
||
|
||
// 将长时间未付款的活跃订阅标记为过期
|
||
$expired_days = apply_filters('yoone_subscription_expiry_days', 30);
|
||
|
||
$updated = $wpdb->query($wpdb->prepare("
|
||
UPDATE {$wpdb->prefix}yoone_subscriptions
|
||
SET status = 'expired', updated_at = %s
|
||
WHERE status = 'active'
|
||
AND next_payment_date < %s
|
||
", current_time('mysql'), date('Y-m-d H:i:s', strtotime("-{$expired_days} days"))));
|
||
|
||
if ($updated > 0) {
|
||
Yoone_Logger::info("标记过期订阅完成: 更新 {$updated} 个订阅");
|
||
|
||
// 发送过期通知邮件
|
||
$this->send_expiry_notifications();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 发送订阅提醒邮件
|
||
*/
|
||
public function send_subscription_reminders() {
|
||
Yoone_Logger::info('开始发送订阅提醒邮件');
|
||
|
||
global $wpdb;
|
||
|
||
// 获取即将到期的订阅(3天内)
|
||
$subscriptions = $wpdb->get_results($wpdb->prepare("
|
||
SELECT s.*, u.user_email, u.display_name
|
||
FROM {$wpdb->prefix}yoone_subscriptions s
|
||
LEFT JOIN {$wpdb->users} u ON s.customer_id = u.ID
|
||
WHERE s.status = 'active'
|
||
AND s.next_payment_date BETWEEN %s AND %s
|
||
AND s.reminder_sent = 0
|
||
", current_time('mysql'), date('Y-m-d H:i:s', strtotime('+3 days'))));
|
||
|
||
$sent = 0;
|
||
|
||
foreach ($subscriptions as $subscription_data) {
|
||
try {
|
||
$this->send_renewal_reminder($subscription_data);
|
||
|
||
// 标记提醒已发送
|
||
$wpdb->update(
|
||
$wpdb->prefix . 'yoone_subscriptions',
|
||
array('reminder_sent' => 1),
|
||
array('id' => $subscription_data->id),
|
||
array('%d'),
|
||
array('%d')
|
||
);
|
||
|
||
$sent++;
|
||
} catch (Exception $e) {
|
||
Yoone_Logger::error('发送提醒邮件失败: ' . $e->getMessage(), array(
|
||
'subscription_id' => $subscription_data->id
|
||
));
|
||
}
|
||
}
|
||
|
||
Yoone_Logger::info("发送订阅提醒邮件完成: 发送 {$sent} 封邮件");
|
||
}
|
||
|
||
/**
|
||
* 清理日志文件
|
||
*/
|
||
public function cleanup_logs() {
|
||
Yoone_Logger::info('开始清理日志文件');
|
||
|
||
$days_to_keep = apply_filters('yoone_log_retention_days', 30);
|
||
Yoone_Logger::cleanup_old_logs($days_to_keep);
|
||
|
||
Yoone_Logger::info("清理日志文件完成: 保留 {$days_to_keep} 天内的日志");
|
||
}
|
||
|
||
/**
|
||
* 发送续费提醒邮件
|
||
*
|
||
* @param object $subscription_data 订阅数据
|
||
*/
|
||
private function send_renewal_reminder($subscription_data) {
|
||
$subject = sprintf(__('您的订阅即将续费 - %s', 'yoone-subscriptions'), get_bloginfo('name'));
|
||
|
||
$message = sprintf(
|
||
__('亲爱的 %s,
|
||
|
||
您的订阅即将在 %s 自动续费。
|
||
|
||
订阅详情:
|
||
- 订阅ID: %d
|
||
- 金额: %s
|
||
- 下次付款日期: %s
|
||
|
||
如需管理您的订阅,请访问:%s
|
||
|
||
谢谢!
|
||
%s', 'yoone-subscriptions'),
|
||
$subscription_data->display_name,
|
||
Yoone_Helper::format_date($subscription_data->next_payment_date, 'Y-m-d'),
|
||
$subscription_data->id,
|
||
wc_price($subscription_data->total),
|
||
Yoone_Helper::format_date($subscription_data->next_payment_date, 'Y-m-d H:i'),
|
||
wc_get_account_endpoint_url('subscriptions'),
|
||
get_bloginfo('name')
|
||
);
|
||
|
||
wp_mail($subscription_data->user_email, $subject, $message);
|
||
}
|
||
|
||
/**
|
||
* 发送过期通知邮件
|
||
*/
|
||
private function send_expiry_notifications() {
|
||
global $wpdb;
|
||
|
||
// 获取刚刚标记为过期的订阅
|
||
$subscriptions = $wpdb->get_results($wpdb->prepare("
|
||
SELECT s.*, u.user_email, u.display_name
|
||
FROM {$wpdb->prefix}yoone_subscriptions s
|
||
LEFT JOIN {$wpdb->users} u ON s.customer_id = u.ID
|
||
WHERE s.status = 'expired'
|
||
AND s.updated_at >= %s
|
||
", date('Y-m-d H:i:s', strtotime('-1 hour'))));
|
||
|
||
foreach ($subscriptions as $subscription_data) {
|
||
$this->send_expiry_notification($subscription_data);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 发送过期通知邮件
|
||
*
|
||
* @param object $subscription_data 订阅数据
|
||
*/
|
||
private function send_expiry_notification($subscription_data) {
|
||
$subject = sprintf(__('您的订阅已过期 - %s', 'yoone-subscriptions'), get_bloginfo('name'));
|
||
|
||
$message = sprintf(
|
||
__('亲爱的 %s,
|
||
|
||
您的订阅已因长时间未付款而过期。
|
||
|
||
订阅详情:
|
||
- 订阅ID: %d
|
||
- 金额: %s
|
||
- 过期时间: %s
|
||
|
||
如需重新激活订阅,请访问:%s
|
||
|
||
谢谢!
|
||
%s', 'yoone-subscriptions'),
|
||
$subscription_data->display_name,
|
||
$subscription_data->id,
|
||
wc_price($subscription_data->total),
|
||
Yoone_Helper::format_date($subscription_data->updated_at, 'Y-m-d H:i'),
|
||
wc_get_account_endpoint_url('subscriptions'),
|
||
get_bloginfo('name')
|
||
);
|
||
|
||
wp_mail($subscription_data->user_email, $subject, $message);
|
||
}
|
||
|
||
/**
|
||
* 取消所有计划事件
|
||
*/
|
||
public static function unschedule_all_events() {
|
||
$events = array(
|
||
'yoone_process_subscription_renewals',
|
||
'yoone_cleanup_expired_tokens',
|
||
'yoone_cleanup_expired_subscriptions',
|
||
'yoone_send_subscription_reminders',
|
||
'yoone_cleanup_logs'
|
||
);
|
||
|
||
foreach ($events as $event) {
|
||
$timestamp = wp_next_scheduled($event);
|
||
if ($timestamp) {
|
||
wp_unschedule_event($timestamp, $event);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 手动触发订阅续费处理
|
||
*/
|
||
public static function manual_process_renewals() {
|
||
$cron = new self();
|
||
$cron->process_subscription_renewals();
|
||
}
|
||
|
||
/**
|
||
* 手动清理过期令牌
|
||
*/
|
||
public static function manual_cleanup_tokens() {
|
||
$cron = new self();
|
||
$cron->cleanup_expired_tokens();
|
||
}
|
||
} |