458 lines
16 KiB
PHP
458 lines
16 KiB
PHP
<?php
|
||
/**
|
||
* Plugin Name: Yoone Subscriptions
|
||
* Plugin URI: https://yoone.ca
|
||
* Description: 专业的WooCommerce混装产品和订阅管理插件,支持Moneris支付网关
|
||
* Version: 1.0.0
|
||
* Author: Yoone Team
|
||
* Author URI: https://yoone.ca
|
||
* Text Domain: yoone-subscriptions
|
||
* Domain Path: /languages
|
||
* Requires at least: 5.0
|
||
* Tested up to: 6.4
|
||
* Requires PHP: 7.4
|
||
* WC requires at least: 5.0
|
||
* WC tested up to: 8.0
|
||
* License: GPL v2 or later
|
||
* License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
||
* Network: false
|
||
*
|
||
* @package YooneSubscriptions
|
||
*/
|
||
|
||
// 防止直接访问
|
||
if (!defined('ABSPATH')) {
|
||
exit;
|
||
}
|
||
|
||
// 检查WooCommerce是否激活
|
||
if (!in_array('woocommerce/woocommerce.php', apply_filters('active_plugins', get_option('active_plugins')))) {
|
||
add_action('admin_notices', function() {
|
||
echo '<div class="notice notice-error"><p><strong>Yoone Subscriptions</strong> 需要 WooCommerce 插件才能正常工作。</p></div>';
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 定义插件常量
|
||
define('YOONE_SUBSCRIPTIONS_VERSION', '1.0.0');
|
||
define('YOONE_SUBSCRIPTIONS_PLUGIN_FILE', __FILE__);
|
||
define('YOONE_SUBSCRIPTIONS_PLUGIN_BASENAME', plugin_basename(__FILE__));
|
||
define('YOONE_SUBSCRIPTIONS_PLUGIN_PATH', plugin_dir_path(__FILE__));
|
||
define('YOONE_SUBSCRIPTIONS_PLUGIN_URL', plugin_dir_url(__FILE__));
|
||
define('YOONE_SUBSCRIPTIONS_INCLUDES_PATH', YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/');
|
||
define('YOONE_SUBSCRIPTIONS_TEMPLATES_PATH', YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'templates/');
|
||
define('YOONE_SUBSCRIPTIONS_ASSETS_URL', YOONE_SUBSCRIPTIONS_PLUGIN_URL . 'assets/');
|
||
|
||
/**
|
||
* 主插件类
|
||
*/
|
||
final class Yoone_Subscriptions {
|
||
|
||
/**
|
||
* 单例实例
|
||
*/
|
||
private static $instance = null;
|
||
|
||
/**
|
||
* 获取单例实例
|
||
*/
|
||
public static function instance() {
|
||
if (is_null(self::$instance)) {
|
||
self::$instance = new self();
|
||
}
|
||
return self::$instance;
|
||
}
|
||
|
||
/**
|
||
* 构造函数
|
||
*/
|
||
private function __construct() {
|
||
$this->init_hooks();
|
||
}
|
||
|
||
/**
|
||
* 初始化钩子
|
||
*/
|
||
private function init_hooks() {
|
||
// 插件激活和停用钩子
|
||
register_activation_hook(__FILE__, array($this, 'activate'));
|
||
register_deactivation_hook(__FILE__, array($this, 'deactivate'));
|
||
|
||
// 插件加载完成后初始化
|
||
add_action('plugins_loaded', array($this, 'init'), 10);
|
||
|
||
// 检查WooCommerce依赖
|
||
add_action('admin_notices', array($this, 'check_woocommerce_dependency'));
|
||
}
|
||
|
||
/**
|
||
* 插件初始化
|
||
*/
|
||
public function init() {
|
||
// 检查WooCommerce是否激活
|
||
if (!$this->is_woocommerce_active()) {
|
||
return;
|
||
}
|
||
|
||
// 加载文本域
|
||
$this->load_textdomain();
|
||
|
||
// 包含核心文件
|
||
$this->includes();
|
||
|
||
// 初始化类
|
||
$this->init_classes();
|
||
|
||
// 初始化钩子
|
||
$this->init_plugin_hooks();
|
||
}
|
||
|
||
/**
|
||
* 检查WooCommerce是否激活
|
||
*/
|
||
private function is_woocommerce_active() {
|
||
return class_exists('WooCommerce');
|
||
}
|
||
|
||
/**
|
||
* 检查WooCommerce依赖
|
||
*/
|
||
public function check_woocommerce_dependency() {
|
||
if (!$this->is_woocommerce_active()) {
|
||
echo '<div class="notice notice-error"><p>';
|
||
echo __('Yoone Subscriptions 需要 WooCommerce 插件才能正常工作。', 'yoone-subscriptions');
|
||
echo '</p></div>';
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 加载文本域
|
||
*/
|
||
private function load_textdomain() {
|
||
load_plugin_textdomain(
|
||
'yoone-subscriptions',
|
||
false,
|
||
dirname(YOONE_SUBSCRIPTIONS_PLUGIN_BASENAME) . '/languages'
|
||
);
|
||
}
|
||
|
||
/**
|
||
* 包含核心文件
|
||
*/
|
||
private function includes() {
|
||
// 核心抽象类和接口
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/abstracts/abstract-yoone-data.php';
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/interfaces/interface-yoone-subscription.php';
|
||
|
||
// 核心类
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/class-yoone-install.php';
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/class-yoone-ajax.php';
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/class-yoone-api.php';
|
||
|
||
// 混装产品层
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/bundle/class-yoone-bundle-product.php';
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/bundle/class-yoone-bundle-cart.php';
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/bundle/class-yoone-bundle-admin.php';
|
||
|
||
// 订阅层
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/subscription/class-yoone-subscription.php';
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/subscription/class-yoone-subscription-manager.php';
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/subscription/class-yoone-subscription-scheduler.php';
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/subscription/class-yoone-subscription-admin.php';
|
||
|
||
// 支付层
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/payment/class-yoone-moneris-gateway.php';
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/payment/class-yoone-payment-token.php';
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/payment/class-yoone-payment-tokens.php';
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/payment/class-yoone-payment-scheduler.php';
|
||
|
||
// 前端类
|
||
if (!is_admin()) {
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/frontend/class-yoone-frontend.php';
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/frontend/class-yoone-shortcodes.php';
|
||
}
|
||
|
||
// 管理后台类
|
||
if (is_admin()) {
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/admin/class-yoone-admin.php';
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/admin/class-yoone-admin-menus.php';
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/admin/class-yoone-admin-settings.php';
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/admin/class-yoone-admin-logs.php';
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/class-yoone-log-analyzer.php';
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'tests/test-config.php';
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'tests/test-subscription-flow.php';
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'tests/class-yoone-test-suite.php';
|
||
}
|
||
|
||
// 工具类
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/class-yoone-logger.php';
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/class-yoone-cache.php';
|
||
require_once YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'includes/class-yoone-helper.php';
|
||
}
|
||
|
||
/**
|
||
* 初始化类
|
||
*/
|
||
private function init_classes() {
|
||
// 初始化前端类
|
||
new Yoone_Frontend();
|
||
|
||
// 初始化后端类
|
||
if (is_admin()) {
|
||
new Yoone_Admin();
|
||
new Yoone_Admin_Logs();
|
||
new Yoone_Test_Suite();
|
||
}
|
||
|
||
// 初始化AJAX类
|
||
new Yoone_Ajax();
|
||
|
||
// 初始化计划任务类
|
||
new Yoone_Cron();
|
||
|
||
// 注册支付网关
|
||
add_filter('woocommerce_payment_gateways', array($this, 'add_payment_gateways'));
|
||
|
||
// 注册产品类型
|
||
add_filter('product_type_selector', array($this, 'add_product_types'));
|
||
add_action('woocommerce_product_data_tabs', array($this, 'add_product_data_tabs'));
|
||
add_action('woocommerce_product_data_panels', array($this, 'add_product_data_panels'));
|
||
}
|
||
|
||
/**
|
||
* 初始化插件钩子
|
||
*/
|
||
private function init_plugin_hooks() {
|
||
// 产品类型和数据面板
|
||
add_filter('product_type_selector', array($this, 'add_product_types'));
|
||
add_filter('woocommerce_product_data_tabs', array($this, 'add_product_data_tabs'));
|
||
add_action('woocommerce_product_data_panels', array($this, 'add_product_data_panels'));
|
||
|
||
// 订阅状态和端点
|
||
add_action('init', array($this, 'register_subscription_statuses'));
|
||
add_action('init', array($this, 'add_subscription_endpoints'));
|
||
|
||
// 管理菜单
|
||
add_action('admin_menu', array($this, 'add_admin_menus'));
|
||
|
||
// 订单状态变化处理
|
||
add_action('woocommerce_order_status_changed', array($this, 'handle_order_status_change'), 10, 4);
|
||
|
||
// 产品元数据保存
|
||
add_action('woocommerce_process_product_meta', array($this, 'save_product_meta'));
|
||
|
||
// 我的账户菜单项
|
||
add_filter('woocommerce_account_menu_items', array($this, 'add_account_menu_items'));
|
||
add_action('woocommerce_account_subscriptions_endpoint', array($this, 'subscriptions_endpoint_content'));
|
||
|
||
// 订阅续费处理
|
||
add_action('yoone_process_subscription_renewals', array($this, 'process_subscription_renewals'));
|
||
|
||
// 清理过期令牌
|
||
add_action('yoone_cleanup_expired_tokens', array($this, 'cleanup_expired_tokens'));
|
||
|
||
// 文本域加载
|
||
add_action('plugins_loaded', array($this, 'load_textdomain'));
|
||
}
|
||
|
||
/**
|
||
* 添加Moneris支付网关
|
||
*/
|
||
public function add_moneris_gateway($gateways) {
|
||
$gateways[] = 'Yoone_Moneris_Gateway';
|
||
return $gateways;
|
||
}
|
||
|
||
/**
|
||
* 初始化核心钩子
|
||
*/
|
||
private function init_core_hooks() {
|
||
// WooCommerce初始化后的钩子
|
||
add_action('woocommerce_init', array($this, 'woocommerce_init'));
|
||
|
||
// 加载模板钩子
|
||
add_filter('woocommerce_locate_template', array($this, 'locate_template'), 10, 3);
|
||
|
||
// 脚本和样式
|
||
add_action('wp_enqueue_scripts', array($this, 'enqueue_scripts'));
|
||
add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'));
|
||
}
|
||
|
||
/**
|
||
* WooCommerce初始化
|
||
*/
|
||
public function woocommerce_init() {
|
||
// 注册自定义产品类型
|
||
add_filter('product_type_selector', array($this, 'add_bundle_product_type'));
|
||
|
||
// 注册自定义订单状态
|
||
add_action('init', array($this, 'register_subscription_statuses'));
|
||
}
|
||
|
||
/**
|
||
* 添加混装产品类型
|
||
*/
|
||
public function add_bundle_product_type($types) {
|
||
$types['bundle'] = __('混装产品', 'yoone-subscriptions');
|
||
return $types;
|
||
}
|
||
|
||
/**
|
||
* 注册订阅状态
|
||
*/
|
||
public function register_subscription_statuses() {
|
||
register_post_status('yoone-active', array(
|
||
'label' => __('激活', 'yoone-subscriptions'),
|
||
'public' => false,
|
||
'show_in_admin_status_list' => true,
|
||
'label_count' => _n_noop('激活 <span class="count">(%s)</span>', '激活 <span class="count">(%s)</span>', 'yoone-subscriptions')
|
||
));
|
||
|
||
register_post_status('yoone-paused', array(
|
||
'label' => __('暂停', 'yoone-subscriptions'),
|
||
'public' => false,
|
||
'show_in_admin_status_list' => true,
|
||
'label_count' => _n_noop('暂停 <span class="count">(%s)</span>', '暂停 <span class="count">(%s)</span>', 'yoone-subscriptions')
|
||
));
|
||
|
||
register_post_status('yoone-cancelled', array(
|
||
'label' => __('已取消', 'yoone-subscriptions'),
|
||
'public' => false,
|
||
'show_in_admin_status_list' => true,
|
||
'label_count' => _n_noop('已取消 <span class="count">(%s)</span>', '已取消 <span class="count">(%s)</span>', 'yoone-subscriptions')
|
||
));
|
||
}
|
||
|
||
/**
|
||
* 定位模板文件
|
||
*/
|
||
public function locate_template($template, $template_name, $template_path) {
|
||
if (strpos($template_name, 'yoone-') === 0) {
|
||
$plugin_template = YOONE_SUBSCRIPTIONS_PLUGIN_PATH . 'templates/' . $template_name;
|
||
if (file_exists($plugin_template)) {
|
||
return $plugin_template;
|
||
}
|
||
}
|
||
return $template;
|
||
}
|
||
|
||
/**
|
||
* 加载前端脚本和样式
|
||
*/
|
||
public function enqueue_scripts() {
|
||
wp_enqueue_style(
|
||
'yoone-subscriptions-frontend',
|
||
YOONE_SUBSCRIPTIONS_PLUGIN_URL . 'assets/css/frontend.css',
|
||
array(),
|
||
YOONE_SUBSCRIPTIONS_VERSION
|
||
);
|
||
|
||
wp_enqueue_script(
|
||
'yoone-subscriptions-frontend',
|
||
YOONE_SUBSCRIPTIONS_PLUGIN_URL . 'assets/js/frontend.js',
|
||
array('jquery', 'wc-add-to-cart'),
|
||
YOONE_SUBSCRIPTIONS_VERSION,
|
||
true
|
||
);
|
||
|
||
// 本地化脚本
|
||
wp_localize_script('yoone-subscriptions-frontend', 'yoone_ajax', array(
|
||
'ajax_url' => admin_url('admin-ajax.php'),
|
||
'nonce' => wp_create_nonce('yoone_nonce'),
|
||
'i18n' => array(
|
||
'loading' => __('加载中...', 'yoone-subscriptions'),
|
||
'error' => __('发生错误,请重试', 'yoone-subscriptions')
|
||
)
|
||
));
|
||
}
|
||
|
||
/**
|
||
* 加载后台脚本和样式
|
||
*/
|
||
public function admin_enqueue_scripts($hook) {
|
||
// 只在相关页面加载
|
||
if (strpos($hook, 'yoone') === false && !in_array($hook, array('post.php', 'post-new.php', 'edit.php'))) {
|
||
return;
|
||
}
|
||
|
||
wp_enqueue_style(
|
||
'yoone-subscriptions-admin',
|
||
YOONE_SUBSCRIPTIONS_PLUGIN_URL . 'assets/css/admin.css',
|
||
array(),
|
||
YOONE_SUBSCRIPTIONS_VERSION
|
||
);
|
||
|
||
wp_enqueue_script(
|
||
'yoone-subscriptions-admin',
|
||
YOONE_SUBSCRIPTIONS_PLUGIN_URL . 'assets/js/admin.js',
|
||
array('jquery', 'wc-enhanced-select'),
|
||
YOONE_SUBSCRIPTIONS_VERSION,
|
||
true
|
||
);
|
||
|
||
wp_localize_script('yoone-subscriptions-admin', 'yoone_admin', array(
|
||
'ajax_url' => admin_url('admin-ajax.php'),
|
||
'nonce' => wp_create_nonce('yoone_admin_nonce')
|
||
));
|
||
}
|
||
|
||
/**
|
||
* 插件激活
|
||
*/
|
||
public function activate() {
|
||
// 检查WooCommerce
|
||
if (!$this->is_woocommerce_active()) {
|
||
deactivate_plugins(YOONE_SUBSCRIPTIONS_PLUGIN_BASENAME);
|
||
wp_die(__('Yoone Subscriptions 需要 WooCommerce 插件才能激活。', 'yoone-subscriptions'));
|
||
}
|
||
|
||
// 创建数据库表
|
||
Yoone_Install::activate();
|
||
|
||
// 设置默认选项
|
||
$this->set_default_options();
|
||
|
||
// 刷新重写规则
|
||
flush_rewrite_rules();
|
||
}
|
||
|
||
/**
|
||
* 插件停用
|
||
*/
|
||
public function deactivate() {
|
||
// 清理定时任务
|
||
wp_clear_scheduled_hook('yoone_process_subscriptions');
|
||
wp_clear_scheduled_hook('yoone_retry_failed_payments');
|
||
|
||
// 刷新重写规则
|
||
flush_rewrite_rules();
|
||
}
|
||
|
||
/**
|
||
* 设置默认选项
|
||
*/
|
||
private function set_default_options() {
|
||
$defaults = array(
|
||
'yoone_bundle_min_quantity' => 10,
|
||
'yoone_subscription_billing_cycle' => 'monthly',
|
||
'yoone_payment_retry_attempts' => 3,
|
||
'yoone_payment_retry_interval' => 24
|
||
);
|
||
|
||
foreach ($defaults as $option => $value) {
|
||
if (get_option($option) === false) {
|
||
add_option($option, $value);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 获取插件主实例
|
||
*/
|
||
function yoone_subscriptions() {
|
||
return Yoone_Subscriptions::instance();
|
||
}
|
||
|
||
// 初始化插件
|
||
yoone_subscriptions(); |