PluginProbe
Subscriptions for WooCommerce with Stripe Recurring Payments / 2.0.0
Subscriptions for WooCommerce with Stripe Recurring Payments v2.0.0
2.0.0 1.11.2 1.11.1 1.11.0 1.10.9 1.10.8 1.10.7 1.10.6 1.10.5 1.10.4 1.10.3 1.10.2 1.10.1 1.10.0 1.9.6 1.9.5 trunk 1.3.0 1.3.1 1.3.2 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 All 61 releases
← All changes | includes/Installer.php +272 -57 1.5.02.0.0 View file →
@@ -1,8 +1,10 @@
1 1 <?php
2 2
3 3 namespace SpringDevs\Subscription;
4 4
5 +use SpringDevs\Subscription\Illuminate\Gateways\Paypal\PaypalDB;
6 +
5 7 /**
6 8 * Class Installer
7 9 *
8 10 * @package SpringDevs\Subscription
@@ -8,74 +10,287 @@
8 10 * @package SpringDevs\Subscription
9 11 */
10 12 class Installer {
11 13
12 - /**
13 - * Run the installer
14 - *
15 - * @return void
16 - */
17 - public function run() {
18 - $this->add_version();
19 - $this->register_schedules();
20 - $this->create_tables();
21 - }
14 + /**
15 + * Database schema version. Bump whenever a custom table changes.
16 + *
17 + * @var string
18 + */
19 + const DB_VERSION = '1.3.0';
22 20
23 - /**
24 - * Add time and version on DB
25 - */
26 - public function add_version() {
27 - $installed = get_option( 'subscrpt_installed' );
21 + /**
22 + * Run the installer
23 + *
24 + * @return void
25 + */
26 + public function run() {
27 + $this->add_version();
28 + $this->register_schedules();
29 + $this->create_tables();
30 + }
28 31
29 - if ( ! $installed ) {
30 - update_option( 'subscrpt_installed', time() );
31 - }
32 + /**
33 + * Create/upgrade custom tables when the stored schema version is outdated.
34 + *
35 + * Lets existing installs pick up new tables on update without a manual
36 + * deactivate/reactivate. A single option read short-circuits once current.
37 + *
38 + * @return void
39 + */
40 + public static function maybe_upgrade() {
41 + if ( get_option( 'subscrpt_db_version' ) === self::DB_VERSION ) {
42 + return;
43 + }
32 44
33 - update_option( 'subscrpt_version', WP_SUBSCRIPTION_VERSION );
45 + ( new self() )->create_tables();
46 + }
34 47
35 - update_option( 'subscrpt_manual_renew_cart_notice', 'Subscriptional product added to cart. Please complete the checkout to renew subscription.' );
36 - }
48 + /**
49 + * Add time and version on DB
50 + */
51 + public function add_version() {
52 + $installed = get_option( 'subscrpt_installed' );
37 53
38 - /**
39 - * Register cron events.
40 - *
41 - * @return void
42 - */
43 - public function register_schedules() {
44 - if ( ! wp_next_scheduled( 'subscrpt_daily_cron' ) ) {
45 - wp_schedule_event( time(), 'daily', 'subscrpt_daily_cron' );
46 - }
54 + if ( ! $installed ) {
55 + update_option( 'subscrpt_installed', time() );
56 + }
47 57
48 - if ( ! wp_next_scheduled( 'subscrpt_renew_reminder_cron' ) ) {
49 - wp_schedule_event( time(), 'daily', 'subscrpt_renew_reminder_cron' );
50 - }
51 - }
58 + update_option( 'subscrpt_version', SUBSCRPT_VERSION );
52 59
53 - /**
54 - * Create necessary database tables
55 - *
56 - * @return void
57 - */
58 - public function create_tables() {
59 - if ( ! function_exists( 'dbDelta' ) ) {
60 - require_once ABSPATH . 'wp-admin/includes/upgrade.php';
61 - }
60 + update_option( 'subscrpt_manual_renew_cart_notice', 'Subscriptional product added to cart. Please complete the checkout to renew subscription.' );
61 + }
62 62
63 - $this->create_histories_table();
64 - }
63 + /**
64 + * Register cron events.
65 + *
66 + * @return void
67 + */
68 + public function register_schedules() {
69 + if ( ! wp_next_scheduled( 'subscrpt_hourly_cron' ) ) {
70 + wp_schedule_event( strtotime( 'tomorrow midnight' ), 'hourly', 'subscrpt_hourly_cron' );
71 + }
72 + }
65 73
66 - /**
67 - * Create histories table
68 - *
69 - * @return void
70 - */
71 - public function create_histories_table() {
72 - global $wpdb;
74 + /**
75 + * Create necessary database tables
76 + *
77 + * @return void
78 + */
79 + public function create_tables() {
80 + if ( ! function_exists( 'dbDelta' ) ) {
81 + require_once ABSPATH . 'wp-admin/includes/upgrade.php';
82 + }
73 83
74 - $charset_collate = $wpdb->get_charset_collate();
75 - $table_name = $wpdb->prefix . 'subscrpt_order_relation';
84 + $this->create_histories_table();
85 + $this->create_stats_snapshot_table();
86 + $this->create_cancellation_feedback_table();
87 + $this->create_plan_group_table();
88 + $this->create_plan_table();
89 + $this->create_plan_relation_table();
90 + PaypalDB::maybe_create_tables();
76 91
77 - $schema = "CREATE TABLE IF NOT EXISTS `{$table_name}` (
92 + update_option( 'subscrpt_db_version', self::DB_VERSION );
93 + }
94 +
95 + /**
96 + * Create the daily stats snapshot table.
97 + *
98 + * One row per calendar day holding the subscription status counts and the
99 + * total monthly recurring revenue (MRR) at snapshot time. Powers MRR/
100 + * subscription "over time" charts in reports and the recovery report.
101 + *
102 + * @return void
103 + */
104 + public function create_stats_snapshot_table() {
105 + global $wpdb;
106 +
107 + $charset_collate = $wpdb->get_charset_collate();
108 + $table_name = $wpdb->prefix . 'subscrpt_stats_snapshot';
109 +
110 + $schema = "CREATE TABLE IF NOT EXISTS `{$table_name}` (
111 + `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
112 + `snapshot_date` DATE NOT NULL,
113 + `active_count` INT(11) NOT NULL DEFAULT 0,
114 + `pending_count` INT(11) NOT NULL DEFAULT 0,
115 + `on_hold_count` INT(11) NOT NULL DEFAULT 0,
116 + `cancelled_count` INT(11) NOT NULL DEFAULT 0,
117 + `expired_count` INT(11) NOT NULL DEFAULT 0,
118 + `pe_cancelled_count` INT(11) NOT NULL DEFAULT 0,
119 + `active_mrr` DECIMAL(14,2) NOT NULL DEFAULT 0,
120 + `created_at` DATETIME NOT NULL,
121 + PRIMARY KEY (`id`),
122 + UNIQUE KEY `snapshot_date` (`snapshot_date`)
123 + ) $charset_collate";
124 +
125 + dbDelta( $schema );
126 + }
127 +
128 + /**
129 + * Create the cancellation survey table.
130 + *
131 + * One row per subscription — the latest cancellation survey (a re-cancel after
132 + * reactivation overwrites the previous row rather than accumulating a log, so
133 + * churn-by-reason reports never double-count a subscription). Stores the
134 + * customer's stated reason (key + a label snapshot that survives later reason
135 + * edits/deletes) and optional comment. Consumed for churn tracking — the recovery
136 + * plugin joins its recovery log to this table on subscription_id.
137 + *
138 + * @return void
139 + */
140 + public function create_cancellation_feedback_table() {
141 + global $wpdb;
142 +
143 + $charset_collate = $wpdb->get_charset_collate();
144 + $table_name = $wpdb->prefix . 'subscrpt_cancellation_feedback';
145 +
146 + $schema = "CREATE TABLE IF NOT EXISTS `{$table_name}` (
147 + `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
148 + `subscription_id` BIGINT(20) UNSIGNED NOT NULL,
149 + `customer_id` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
150 + `reason_key` VARCHAR(60) NOT NULL DEFAULT '',
151 + `reason_label` VARCHAR(191) NOT NULL DEFAULT '',
152 + `comment` TEXT NULL,
153 + `created_at` DATETIME NOT NULL,
154 + PRIMARY KEY (`id`),
155 + KEY `subscription_id` (`subscription_id`),
156 + KEY `created_at` (`created_at`)
157 + ) $charset_collate";
158 +
159 + dbDelta( $schema );
160 + }
161 +
162 + /**
163 + * Create the subscription plan group table.
164 + *
165 + * A plan group is a named, reusable subscription plan (e.g. "Premium
166 + * Membership") attached to one or more products. This is the free base
167 + * schema; Pro adds columns on top via versioned migrations keyed on
168 + * `subscrpt_db_version`.
169 + *
170 + * type: 1 = Subscribe & Save, 2 = Recurring, 3 = Installment (free writes 2).
171 + * product_type: 1 = specific products, 2 = taxonomy (free writes 1).
172 + * data: JSON (group-level settings).
173 + *
174 + * @return void
175 + */
176 + public function create_plan_group_table() {
177 + global $wpdb;
178 +
179 + $charset_collate = $wpdb->get_charset_collate();
180 + $table_name = $wpdb->prefix . 'subscrpt_plan_group';
181 +
182 + $schema = "CREATE TABLE IF NOT EXISTS `{$table_name}` (
183 + `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
184 + `type` TINYINT(2) NOT NULL DEFAULT 2,
185 + `product_type` TINYINT(2) NOT NULL DEFAULT 1,
186 + `title` VARCHAR(255) NOT NULL DEFAULT '',
187 + `status` VARCHAR(20) NOT NULL DEFAULT 'active',
188 + `data` LONGTEXT NULL,
189 + `created_at` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
190 + `updated_at` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
191 + PRIMARY KEY (`id`),
192 + KEY `type` (`type`),
193 + KEY `status` (`status`)
194 + ) $charset_collate";
195 +
196 + dbDelta( $schema );
197 + }
198 +
199 + /**
200 + * Create the subscription plan (term) table.
201 + *
202 + * A plan is one billing term inside a group (e.g. "every 1 month"). There is
203 + * no price column — pricing lives per product on the relation.
204 + *
205 + * billing_interval: 1 = day, 2 = week, 3 = month, 4 = year.
206 + * billing_length: expiry in cycles, 0 = unlimited.
207 + * price_mode: snapshot (default) | live (free always snapshot).
208 + *
209 + * @return void
210 + */
211 + public function create_plan_table() {
212 + global $wpdb;
213 +
214 + $charset_collate = $wpdb->get_charset_collate();
215 + $table_name = $wpdb->prefix . 'subscrpt_plan';
216 +
217 + $schema = "CREATE TABLE IF NOT EXISTS `{$table_name}` (
218 + `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
219 + `plan_group_id` BIGINT(20) UNSIGNED NOT NULL,
220 + `title` VARCHAR(255) NOT NULL DEFAULT '',
221 + `type` TINYINT(2) NOT NULL DEFAULT 2,
222 + `billing_frequency` INT(11) NOT NULL DEFAULT 1,
223 + `billing_interval` TINYINT(2) NOT NULL DEFAULT 3,
224 + `billing_length` INT(11) NOT NULL DEFAULT 0,
225 + `signup_fee` LONGTEXT NULL,
226 + `free_trial` VARCHAR(50) NOT NULL DEFAULT '',
227 + `prepaid` TINYINT(1) NOT NULL DEFAULT 0,
228 + `offer` LONGTEXT NULL,
229 + `price_mode` VARCHAR(20) NOT NULL DEFAULT 'snapshot',
230 + `status` VARCHAR(20) NOT NULL DEFAULT 'active',
231 + `data` LONGTEXT NULL,
232 + `created_at` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
233 + `updated_at` DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00',
234 + PRIMARY KEY (`id`),
235 + KEY `plan_group_id` (`plan_group_id`),
236 + KEY `status` (`status`)
237 + ) $charset_collate";
238 +
239 + dbDelta( $schema );
240 + }
241 +
242 + /**
243 + * Create the subscription plan relation table.
244 + *
245 + * The many-to-many join between a plan term and a product, carrying the
246 + * per-product price in its `data` JSON.
247 + *
248 + * oid: product id (type 1) or term id (type 2).
249 + * vid: variation id; 0 for simple products (free always 0).
250 + * type: 1 = product, 2 = taxonomy.
251 + * data: JSON price override (regular_price, sale_price, discount_type,
252 + * discount_value).
253 + * exclude: per-row toggle to hide one term for one product.
254 + *
255 + * @return void
256 + */
257 + public function create_plan_relation_table() {
258 + global $wpdb;
259 +
260 + $charset_collate = $wpdb->get_charset_collate();
261 + $table_name = $wpdb->prefix . 'subscrpt_plan_relation';
262 +
263 + $schema = "CREATE TABLE IF NOT EXISTS `{$table_name}` (
264 + `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
265 + `plan_id` BIGINT(20) UNSIGNED NOT NULL,
266 + `oid` BIGINT(20) UNSIGNED NOT NULL,
267 + `vid` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
268 + `type` TINYINT(2) NOT NULL DEFAULT 1,
269 + `data` LONGTEXT NULL,
270 + `exclude` TINYINT(1) NOT NULL DEFAULT 0,
271 + `status` VARCHAR(20) NOT NULL DEFAULT 'active',
272 + PRIMARY KEY (`id`),
273 + KEY `plan_id` (`plan_id`),
274 + KEY `plan_lookup` (`plan_id`,`type`,`oid`,`vid`),
275 + KEY `product_lookup` (`type`,`oid`,`vid`)
276 + ) $charset_collate";
277 +
278 + dbDelta( $schema );
279 + }
280 +
281 + /**
282 + * Create histories table
283 + *
284 + * @return void
285 + */
286 + public function create_histories_table() {
287 + global $wpdb;
288 +
289 + $charset_collate = $wpdb->get_charset_collate();
290 + $table_name = $wpdb->prefix . 'subscrpt_order_relation';
291 +
292 + $schema = "CREATE TABLE IF NOT EXISTS `{$table_name}` (
78 293 `id` INT(255) NOT NULL AUTO_INCREMENT,
79 294 `subscription_id` INT(100) NOT NULL,
80 295 `order_id` INT(100) NOT NULL,
81 296 `order_item_id` INT(100) NOT NULL,
@@ -82,7 +297,7 @@
82 297 `type` VARCHAR(50) NOT NULL,
83 298 PRIMARY KEY (`id`)
84 299 ) $charset_collate";
85 300
86 - dbDelta( $schema );
87 - }
301 + dbDelta( $schema );
302 + }
88 303 }