PluginProbe
Recurio – Ultimate Subscription for WooCommerce / 1.0.2
Recurio – Ultimate Subscription for WooCommerce v1.0.2
1.1.6 1.1.5 1.1.4 1.1.3 1.1.2 1.1.1 trunk 1.0.0 1.0.1 1.0.2 1.1.0
recurio / recurio.php

recurio.php in Recurio – Ultimate Subscription for WooCommerce 1.0.2, at recurio.php

460 lines 15.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: Recurio – Ultimate Subscription for WooCommerce
4 * Description: Ultimate Subscription Plugin for WooCommerce
5 * Version: 1.0.2
6 * Author: DevItems
7 * Author URI: https://devitems.com
8 * Plugin URI: https://wprecurio.com
9 * License: GPL v2 or later
10 * Text Domain: recurio
11 * Domain Path: /languages
12 * Requires at least: 5.8
13 * Requires PHP: 7.4
14 * WC requires at least: 8.0
15 * WC tested up to: 10.7.0
16 */
17
18 // Prevent direct access
19 if ( ! defined( 'ABSPATH' ) ) {
20 exit;
21 }
22
23 // Define plugin constants
24 define( 'RECURIO_VERSION', '1.0.2' );
25 define( 'RECURIO_PLUGIN_FILE', __FILE__ );
26 define( 'RECURIO_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
27 define( 'RECURIO_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
28 define( 'RECURIO_PLUGIN_BASENAME', plugin_basename( __FILE__ ) );
29
30 // Check if WooCommerce is active
31 function recurio_check_woocommerce() {
32 if ( ! class_exists( 'WooCommerce' ) ) {
33 add_action(
34 'admin_notices',
35 function () {
36 ?>
37 <div class="notice notice-error is-dismissible">
38 <p><?php esc_html_e( 'Recurio requires WooCommerce to be installed and active.', 'recurio' ); ?></p>
39 </div>
40 <?php
41 }
42 );
43 return false;
44 }
45 return true;
46 }
47
48 // Main plugin class
49 class Recurio {
50
51 private static $instance = null;
52
53 public static function get_instance() {
54 if ( null === self::$instance ) {
55 self::$instance = new self();
56 }
57 return self::$instance;
58 }
59
60 private function __construct() {
61 $this->init_hooks();
62 }
63
64 private function init_hooks() {
65 add_action( 'plugins_loaded', array( $this, 'load_plugin' ) );
66 add_action( 'init', array( $this, 'init' ) );
67
68 // Activation and deactivation hooks
69 register_activation_hook( RECURIO_PLUGIN_FILE, array( $this, 'activate' ) );
70 register_deactivation_hook( RECURIO_PLUGIN_FILE, array( $this, 'deactivate' ) );
71
72 // Compatible With WooCommerce Custom Order Tables
73 $this->compatibility_woocommerce_custom_order();
74 }
75
76 public function load_plugin() {
77 if ( ! recurio_check_woocommerce() ) {
78 return;
79 }
80
81 // Check for database upgrades
82 $this->maybe_upgrade_database();
83
84 // Load required files
85 $this->load_includes();
86
87 // Initialize components
88 $this->init_components();
89 }
90
91 /**
92 * Check and upgrade database if needed
93 */
94 private function maybe_upgrade_database() {
95 $db_version = get_option( 'recurio_db_version', '1.0.0' );
96
97 // Version 1.1.0 - Add custom access duration columns
98 if ( version_compare( $db_version, '1.0.1', '<' ) ) {
99 $this->upgrade_to_1_1_0();
100 update_option( 'recurio_db_version', '1.0.1' );
101 }
102
103 }
104
105 /**
106 * Database upgrade to version 1.1.0
107 * Adds custom access duration columns for split payments
108 */
109 private function upgrade_to_1_1_0() {
110 global $wpdb;
111
112 $table_name = $wpdb->prefix . 'recurio_subscriptions';
113
114 // Check if columns exist before adding
115 $columns = $wpdb->get_col( "SHOW COLUMNS FROM {$table_name}" );
116
117 if ( ! in_array( 'access_duration_value', $columns, true ) ) {
118 $wpdb->query( "ALTER TABLE {$table_name} ADD COLUMN access_duration_value INT DEFAULT 1 AFTER access_timing" );
119 }
120
121 if ( ! in_array( 'access_duration_unit', $columns, true ) ) {
122 $wpdb->query( "ALTER TABLE {$table_name} ADD COLUMN access_duration_unit VARCHAR(20) DEFAULT 'month' AFTER access_duration_value" );
123 }
124
125 if ( ! in_array( 'access_end_date', $columns, true ) ) {
126 $wpdb->query( "ALTER TABLE {$table_name} ADD COLUMN access_end_date DATETIME DEFAULT NULL AFTER access_duration_unit" );
127 }
128
129 if ( ! in_array( 'switched_from_id', $columns, true ) ) {
130 $wpdb->query( "ALTER TABLE {$table_name} ADD COLUMN switched_from_id BIGINT DEFAULT NULL AFTER access_end_date" );
131 }
132
133 if ( ! in_array( 'switched_to_id', $columns, true ) ) {
134 $wpdb->query( "ALTER TABLE {$table_name} ADD COLUMN switched_to_id BIGINT DEFAULT NULL AFTER switched_from_id" );
135 }
136
137 if ( ! in_array( 'switch_type', $columns, true ) ) {
138 $wpdb->query( "ALTER TABLE {$table_name} ADD COLUMN switch_type VARCHAR(20) DEFAULT NULL AFTER switched_to_id" );
139 }
140 }
141
142 public function compatibility_woocommerce_custom_order(){
143 // Compatible With WooCommerce Custom Order Tables
144 add_action( 'before_woocommerce_init', function() {
145 if ( class_exists( '\Automattic\WooCommerce\Utilities\FeaturesUtil' ) ) {
146 \Automattic\WooCommerce\Utilities\FeaturesUtil::declare_compatibility( 'custom_order_tables', __FILE__, true );
147 }
148 } );
149 }
150
151 public function init() {
152 // Initialize post types, taxonomies, etc.
153 do_action( 'recurio_init' );
154 }
155
156 private function load_includes() {
157 // Pro Manager (must load first)
158 require_once RECURIO_PLUGIN_DIR . 'includes/core/class-pro-manager.php';
159
160 // Core classes
161 require_once RECURIO_PLUGIN_DIR . 'includes/core/class-subscription-engine.php';
162 require_once RECURIO_PLUGIN_DIR . 'includes/core/class-email-notifications.php';
163 require_once RECURIO_PLUGIN_DIR . 'includes/core/class-billing-manager.php';
164 require_once RECURIO_PLUGIN_DIR . 'includes/core/class-payment-methods.php';
165 require_once RECURIO_PLUGIN_DIR . 'includes/core/class-changelog-manager.php';
166 // Subscription Switching is a PRO feature - loaded by recurio-pro plugin
167
168 // Admin classes
169 require_once RECURIO_PLUGIN_DIR . 'includes/admin/class-dashboard.php';
170 require_once RECURIO_PLUGIN_DIR . 'includes/admin/class-vue-app.php';
171 require_once RECURIO_PLUGIN_DIR . 'includes/admin/class-wc-subscriptions-importer.php';
172
173 // WooCommerce integration
174 if ( class_exists( 'WooCommerce' ) ) {
175 require_once RECURIO_PLUGIN_DIR . 'includes/integrations/class-woocommerce-product.php';
176 }
177
178 // Frontend classes
179 require_once RECURIO_PLUGIN_DIR . 'includes/frontend/class-customer-portal.php';
180
181 // Admin classes
182 require_once RECURIO_PLUGIN_DIR . 'includes/admin/class-pro-upsell.php';
183
184 // Integration classes
185 require_once RECURIO_PLUGIN_DIR . 'includes/integrations/class-woocommerce.php';
186
187 // API classes
188 require_once RECURIO_PLUGIN_DIR . 'includes/api/class-rest-api.php';
189 }
190
191 private function init_components() {
192 // Initialize Pro Manager first
193 Recurio_Pro_Manager::get_instance();
194
195 // Initialize core components
196 Recurio_Subscription_Engine::get_instance();
197 Recurio_Email_Notifications::get_instance();
198 Recurio_Billing_Manager::get_instance();
199 Recurio_Payment_Methods::get_instance();
200 // Subscription Switching is initialized by PRO plugin
201
202 // Initialize admin components
203 if ( is_admin() ) {
204 Recurio_Dashboard::get_instance();
205 Recurio_Vue_App::get_instance();
206 Recurio_Pro_Upsell::get_instance();
207 Recurio_WC_Subscriptions_Importer::get_instance();
208 }
209
210 // Initialize frontend components
211 // Note: AJAX requests are considered admin requests, so we need to initialize for AJAX too
212 if ( ! is_admin() || wp_doing_ajax() ) {
213 Recurio_Customer_Portal::get_instance();
214 }
215
216 // Initialize integrations
217 Recurio_WooCommerce_Integration::get_instance();
218
219 // Initialize API
220 Recurio_Rest_API::get_instance();
221 }
222
223 public function activate() {
224 // Create database tables
225 $this->create_database_tables();
226
227 // Set default options
228 $this->set_default_options();
229
230 // Schedule cron jobs
231 $this->schedule_cron_jobs();
232
233 // Set flag to flush rewrite rules on next page load
234 // This ensures endpoints are properly registered before flushing
235 update_option( 'recurio_flush_rewrite_rules', true );
236 }
237
238 public function deactivate() {
239 // Clear scheduled cron jobs
240 $this->clear_cron_jobs();
241
242 // Flush rewrite rules immediately to remove custom endpoints
243 flush_rewrite_rules();
244 }
245
246 private function create_database_tables() {
247 global $wpdb;
248
249 $charset_collate = $wpdb->get_charset_collate();
250
251 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
252
253 // Subscriptions table
254 $table_name = $wpdb->prefix . 'recurio_subscriptions';
255 $sql = "CREATE TABLE $table_name (
256 id BIGINT PRIMARY KEY AUTO_INCREMENT,
257 wc_subscription_id BIGINT,
258 customer_id BIGINT NOT NULL,
259 product_id BIGINT NOT NULL,
260 status VARCHAR(20) DEFAULT 'active',
261 billing_period VARCHAR(20) NOT NULL,
262 billing_interval INT DEFAULT 1,
263 billing_amount DECIMAL(10,2) NOT NULL,
264 payment_method VARCHAR(50) DEFAULT NULL,
265 payment_token_id BIGINT DEFAULT NULL,
266 billing_address TEXT,
267 shipping_address TEXT,
268 trial_end_date DATETIME,
269 next_payment_date DATETIME,
270 pause_start_date DATETIME,
271 pause_end_date DATETIME,
272 cancellation_date DATETIME,
273 cancellation_reason TEXT,
274 failed_payment_count INT DEFAULT 0,
275 renewal_count INT DEFAULT 0,
276 max_renewals INT DEFAULT NULL,
277 payment_type VARCHAR(20) DEFAULT 'recurring',
278 max_payments INT DEFAULT 0,
279 access_timing VARCHAR(50) DEFAULT 'immediate',
280 access_duration_value INT DEFAULT 1,
281 access_duration_unit VARCHAR(20) DEFAULT 'month',
282 access_end_date DATETIME DEFAULT NULL,
283 switched_from_id BIGINT DEFAULT NULL,
284 switched_to_id BIGINT DEFAULT NULL,
285 switch_type VARCHAR(20) DEFAULT NULL,
286 churn_risk_score DECIMAL(3,2) DEFAULT 0,
287 customer_ltv DECIMAL(10,2),
288 subscription_metadata LONGTEXT,
289 created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
290 updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
291 INDEX idx_status (status),
292 INDEX idx_next_payment (next_payment_date),
293 INDEX idx_churn_risk (churn_risk_score),
294 INDEX idx_payment_type (payment_type)
295 ) $charset_collate;";
296 dbDelta( $sql );
297
298 // Subscription events table
299 $table_name = $wpdb->prefix . 'recurio_subscription_events';
300 $sql = "CREATE TABLE $table_name (
301 id BIGINT PRIMARY KEY AUTO_INCREMENT,
302 subscription_id BIGINT NOT NULL,
303 event_type VARCHAR(50) NOT NULL,
304 event_value DECIMAL(10,2),
305 event_metadata LONGTEXT,
306 created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
307 INDEX idx_recurio_subscription_events (subscription_id, created_at),
308 INDEX idx_event_type (event_type)
309 ) $charset_collate;";
310 dbDelta( $sql );
311
312 // Revenue tracking table
313 $table_name = $wpdb->prefix . 'recurio_subscription_revenue';
314 $sql = "CREATE TABLE $table_name (
315 id BIGINT PRIMARY KEY AUTO_INCREMENT,
316 subscription_id BIGINT NOT NULL,
317 amount DECIMAL(10,2) NOT NULL,
318 currency VARCHAR(3) DEFAULT 'USD',
319 period_type VARCHAR(20),
320 period_start DATE,
321 period_end DATE,
322 transaction_id VARCHAR(100),
323 gateway VARCHAR(50),
324 payment_method VARCHAR(50),
325 created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
326 INDEX idx_revenue_date (period_start, period_end),
327 INDEX idx_recurio_subscription_revenue (subscription_id)
328 ) $charset_collate;";
329 dbDelta( $sql );
330
331 // Customer analytics table
332 $table_name = $wpdb->prefix . 'recurio_customer_analytics';
333 $sql = "CREATE TABLE $table_name (
334 id BIGINT PRIMARY KEY AUTO_INCREMENT,
335 customer_id BIGINT NOT NULL,
336 total_subscriptions INT DEFAULT 0,
337 active_subscriptions INT DEFAULT 0,
338 total_revenue DECIMAL(10,2) DEFAULT 0,
339 average_order_value DECIMAL(10,2),
340 churn_probability DECIMAL(3,2) DEFAULT 0,
341 customer_lifetime_value DECIMAL(10,2),
342 last_activity_date DATETIME,
343 customer_segment VARCHAR(50),
344 updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
345 UNIQUE KEY unique_customer (customer_id)
346 ) $charset_collate;";
347 dbDelta( $sql );
348
349 // Revenue goals table (added in v1.5 but created here for new installs)
350 $table_name = $wpdb->prefix . 'recurio_revenue_goals';
351 $sql = "CREATE TABLE $table_name (
352 id BIGINT PRIMARY KEY AUTO_INCREMENT,
353 name VARCHAR(255) NOT NULL,
354 target_amount DECIMAL(10,2) NOT NULL,
355 current_amount DECIMAL(10,2) DEFAULT 0,
356 period_type VARCHAR(20) NOT NULL,
357 start_date DATE NOT NULL,
358 end_date DATE NOT NULL,
359 status VARCHAR(20) DEFAULT 'active',
360 created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
361 updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
362 INDEX idx_status (status),
363 INDEX idx_dates (start_date, end_date),
364 INDEX idx_period (period_type)
365 ) $charset_collate;";
366 dbDelta( $sql );
367
368 // Webhooks table
369 $table_name = $wpdb->prefix . 'recurio_webhooks';
370 $sql = "CREATE TABLE $table_name (
371 id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
372 name varchar(255) NOT NULL,
373 url varchar(500) NOT NULL,
374 events longtext NOT NULL COMMENT 'JSON array of event names',
375 secret varchar(64) NOT NULL COMMENT 'HMAC secret for signature verification',
376 status varchar(20) NOT NULL DEFAULT 'active' COMMENT 'active, paused, failed',
377 failure_count int(11) NOT NULL DEFAULT 0,
378 last_triggered_at datetime DEFAULT NULL,
379 created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
380 updated_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
381 PRIMARY KEY (id),
382 KEY status (status)
383 ) $charset_collate;";
384 dbDelta( $sql );
385
386 // Webhook logs table
387 $table_name = $wpdb->prefix . 'recurio_webhook_logs';
388 $sql = "CREATE TABLE $table_name (
389 id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
390 webhook_id bigint(20) UNSIGNED NOT NULL,
391 event varchar(100) NOT NULL,
392 payload longtext NOT NULL COMMENT 'JSON payload sent',
393 response_code int(11) DEFAULT NULL,
394 response_body text DEFAULT NULL,
395 response_time int(11) DEFAULT NULL COMMENT 'Response time in milliseconds',
396 success tinyint(1) NOT NULL DEFAULT 0,
397 attempt_number int(11) NOT NULL DEFAULT 1,
398 error_message text DEFAULT NULL,
399 created_at datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
400 PRIMARY KEY (id),
401 KEY webhook_id (webhook_id),
402 KEY event (event),
403 KEY success (success),
404 KEY created_at (created_at)
405 ) $charset_collate;";
406 dbDelta( $sql );
407 }
408
409 private function set_default_options() {
410 add_option( 'recurio_version', RECURIO_VERSION );
411 add_option(
412 'recurio_settings',
413 array(
414 'enable_customer_portal' => true,
415 'dunning_attempts' => 3,
416 'dunning_interval' => 3,
417 'enable_analytics' => true,
418 'currency' => 'USD',
419 'date_format' => 'Y-m-d',
420 'enable_debug' => false,
421 'billing' => array(
422 'periods' => array( 'daily', 'weekly', 'monthly', 'quarterly', 'yearly' ),
423 'autoRenewal' => true,
424 'enableProration' => true,
425 'trialLength' => 14,
426 'trialUnit' => 'days',
427 ),
428 )
429 );
430 }
431
432 private function schedule_cron_jobs() {
433
434 if ( ! wp_next_scheduled( 'recurio_process_payments' ) ) {
435 wp_schedule_event( time(), 'daily', 'recurio_process_payments' );
436 }
437
438 if ( ! wp_next_scheduled( 'recurio_calculate_analytics' ) ) {
439 wp_schedule_event( time(), 'hourly', 'recurio_calculate_analytics' );
440 }
441
442 if ( ! wp_next_scheduled( 'recurio_predict_churn' ) ) {
443 wp_schedule_event( time(), 'daily', 'recurio_predict_churn' );
444 }
445
446 if ( ! wp_next_scheduled( 'recurio_send_renewal_reminders' ) ) {
447 wp_schedule_event( time(), 'daily', 'recurio_send_renewal_reminders' );
448 }
449 }
450
451 private function clear_cron_jobs() {
452 wp_clear_scheduled_hook( 'recurio_process_payments' );
453 wp_clear_scheduled_hook( 'recurio_calculate_analytics' );
454 wp_clear_scheduled_hook( 'recurio_predict_churn' );
455 wp_clear_scheduled_hook( 'recurio_send_renewal_reminders' );
456 }
457 }
458
459 // Initialize the plugin
460 Recurio::get_instance();