subscription/includes/class-yoone-cron.php

363 lines
11 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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();
}
}