Passed
Push — master ( 200337...fb8ed7 )
by Brian
08:10 queued 03:45
created

GetPaid_Installer::get_db_schema_version()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 4
nc 2
nop 0
dl 0
loc 8
rs 10
c 0
b 0
f 0
1
<?php
2
/**
3
 * Contains the main installer class.
4
 *
5
 * @package GetPaid
6
 * @subpackage Admin
7
 * @version 2.0.2
8
 * @since   2.0.2
9
 */
10
11
defined( 'ABSPATH' ) || exit;
12
13
/**
14
 * The main installer/updater class.
15
 *
16
 * @package GetPaid
17
 * @subpackage Admin
18
 * @version 2.0.2
19
 * @since   2.0.2
20
 */
21
class GetPaid_Installer {
22
23
	private static $schema = null;
24
	private static $schema_version = null;
25
26
	/**
27
	 * Upgrades the install.
28
	 *
29
	 * @param string $upgrade_from The current invoicing version.
30
	 */
31
	public function upgrade_db( $upgrade_from ) {
32
33
		// Save the current invoicing version.
34
		update_option( 'wpinv_version', WPINV_VERSION );
35
36
		// Setup the invoice Custom Post Type.
37
		GetPaid_Post_Types::register_post_types();
38
39
		// Clear the permalinks
40
		flush_rewrite_rules();
41
42
		// Maybe create new/missing pages.
43
		$this->create_pages();
44
45
		// Maybe re(add) admin capabilities.
46
		$this->add_capabilities();
47
48
		// Maybe create the default payment form.
49
		wpinv_get_default_payment_form();
50
51
		// Create any missing database tables.
52
		$method = "upgrade_from_$upgrade_from";
53
54
		$installed = get_option( 'gepaid_installed_on' );
55
56
		if ( empty( $installed ) ) {
57
			update_option( 'gepaid_installed_on', time() );
58
		}
59
60
		if ( method_exists( $this, $method ) ) {
61
			$this->$method();
62
		}
63
64
	}
65
66
	/**
67
	 * Do a fresh install.
68
	 *
69
	 */
70
	public function upgrade_from_0() {
71
72
		// Save default tax rates.
73
		update_option( 'wpinv_tax_rates', wpinv_get_data( 'tax-rates' ) );
74
	}
75
76
	/**
77
	 * Upgrade to 0.0.5
78
	 *
79
	 */
80
	public function upgrade_from_004() {
81
		global $wpdb;
82
83
		// Invoices.
84
		$results = $wpdb->get_results( "SELECT ID FROM {$wpdb->posts} WHERE post_type = 'wpi_invoice' AND post_status IN( 'pending', 'processing', 'onhold', 'refunded', 'cancelled', 'failed', 'renewal' )" );
85
		if ( ! empty( $results ) ) {
86
			$wpdb->query( "UPDATE {$wpdb->posts} SET post_status = CONCAT( 'wpi-', post_status ) WHERE post_type = 'wpi_invoice' AND post_status IN( 'pending', 'processing', 'onhold', 'refunded', 'cancelled', 'failed', 'renewal' )" );
87
88
			// Clean post cache
89
			foreach ( $results as $row ) {
90
				clean_post_cache( $row->ID );
91
			}
92
		}
93
94
		// Item meta key changes
95
		$query = 'SELECT DISTINCT post_id FROM ' . $wpdb->postmeta . " WHERE meta_key IN( '_wpinv_item_id', '_wpinv_package_id', '_wpinv_post_id', '_wpinv_cpt_name', '_wpinv_cpt_singular_name' )";
96
		$results = $wpdb->get_results( $query );
97
98
		if ( ! empty( $results ) ) {
99
			$wpdb->query( 'UPDATE ' . $wpdb->postmeta . " SET meta_key = '_wpinv_custom_id' WHERE meta_key IN( '_wpinv_item_id', '_wpinv_package_id', '_wpinv_post_id' )" );
100
			$wpdb->query( 'UPDATE ' . $wpdb->postmeta . " SET meta_key = '_wpinv_custom_name' WHERE meta_key = '_wpinv_cpt_name'" );
101
			$wpdb->query( 'UPDATE ' . $wpdb->postmeta . " SET meta_key = '_wpinv_custom_singular_name' WHERE meta_key = '_wpinv_cpt_singular_name'" );
102
103
			foreach ( $results as $row ) {
104
				clean_post_cache( $row->post_id );
105
			}
106
		}
107
108
		$this->upgrade_from_118();
109
	}
110
111
	/**
112
	 * Upgrade to version 2.0.0.
113
	 *
114
	 */
115
	public function upgrade_from_118() {
116
		$this->migrate_old_invoices();
117
		$this->upgrade_from_279();
118
	}
119
120
	/**
121
	 * Upgrade to version 2.0.0.
122
	 *
123
	 */
124
	public function upgrade_from_279() {
125
		self::migrate_old_customers();
126
	}
127
128
	/**
129
	 * Give administrators the capability to manage GetPaid.
130
	 *
131
	 */
132
	public function add_capabilities() {
133
		$GLOBALS['wp_roles']->add_cap( 'administrator', 'manage_invoicing' );
134
	}
135
136
	/**
137
	 * Retreives GetPaid pages.
138
	 *
139
	 */
140
	public static function get_pages() {
141
142
		return apply_filters(
143
			'wpinv_create_pages',
144
			array(
145
146
				// Checkout page.
147
				'checkout_page'             => array(
148
					'name'    => _x( 'gp-checkout', 'Page slug', 'invoicing' ),
149
					'title'   => _x( 'Checkout', 'Page title', 'invoicing' ),
150
					'content' => '
151
						<!-- wp:shortcode -->
152
						[wpinv_checkout]
153
						<!-- /wp:shortcode -->
154
					',
155
					'parent'  => '',
156
				),
157
158
				// Invoice history page.
159
				'invoice_history_page'      => array(
160
					'name'    => _x( 'gp-invoices', 'Page slug', 'invoicing' ),
161
					'title'   => _x( 'My Invoices', 'Page title', 'invoicing' ),
162
					'content' => '
163
					<!-- wp:shortcode -->
164
					[wpinv_history]
165
					<!-- /wp:shortcode -->
166
				',
167
					'parent'  => '',
168
				),
169
170
				// Success page content.
171
				'success_page'              => array(
172
					'name'    => _x( 'gp-receipt', 'Page slug', 'invoicing' ),
173
					'title'   => _x( 'Payment Confirmation', 'Page title', 'invoicing' ),
174
					'content' => '
175
					<!-- wp:shortcode -->
176
					[wpinv_receipt]
177
					<!-- /wp:shortcode -->
178
				',
179
					'parent'  => 'gp-checkout',
180
				),
181
182
				// Failure page content.
183
				'failure_page'              => array(
184
					'name'    => _x( 'gp-transaction-failed', 'Page slug', 'invoicing' ),
185
					'title'   => _x( 'Transaction Failed', 'Page title', 'invoicing' ),
186
					'content' => __( 'Your transaction failed, please try again or contact site support.', 'invoicing' ),
187
					'parent'  => 'gp-checkout',
188
				),
189
190
				// Subscriptions history page.
191
				'invoice_subscription_page' => array(
192
					'name'    => _x( 'gp-subscriptions', 'Page slug', 'invoicing' ),
193
					'title'   => _x( 'My Subscriptions', 'Page title', 'invoicing' ),
194
					'content' => '
195
					<!-- wp:shortcode -->
196
					[wpinv_subscriptions]
197
					<!-- /wp:shortcode -->
198
				',
199
					'parent'  => '',
200
				),
201
202
			)
203
		);
204
205
	}
206
207
	/**
208
	 * Re-create GetPaid pages.
209
	 *
210
	 */
211
	public function create_pages() {
212
213
		foreach ( self::get_pages() as $key => $page ) {
214
			wpinv_create_page( esc_sql( $page['name'] ), $key, $page['title'], $page['content'], $page['parent'] );
215
		}
216
217
	}
218
219
	/**
220
	 * Migrates old invoices to new invoices.
221
	 *
222
	 */
223
	public function migrate_old_invoices() {
224
		global $wpdb;
225
226
		$invoices_table      = $wpdb->prefix . 'getpaid_invoices';
227
		$invoice_items_table = $wpdb->prefix . 'getpaid_invoice_items';
228
		$migrated            = $wpdb->get_col( "SELECT post_id FROM $invoices_table" );
229
		$invoices            = array_unique(
230
			get_posts(
231
				array(
232
					'post_type'      => array( 'wpi_invoice', 'wpi_quote' ),
233
					'posts_per_page' => -1,
234
					'fields'         => 'ids',
235
					'post_status'    => array_keys( get_post_stati() ),
236
					'exclude'        => (array) $migrated,
237
				)
238
			)
239
		);
240
241
		// Abort if we do not have any invoices.
242
		if ( empty( $invoices ) ) {
243
			return;
244
		}
245
246
		require_once WPINV_PLUGIN_DIR . 'includes/class-wpinv-legacy-invoice.php';
247
248
		$invoice_rows = array();
249
		foreach ( $invoices as $invoice ) {
250
251
			$invoice = new WPInv_Legacy_Invoice( $invoice );
252
253
			if ( empty( $invoice->ID ) ) {
254
				return;
255
			}
256
257
			$fields = array(
258
				'post_id'            => $invoice->ID,
259
				'number'             => $invoice->get_number(),
260
				'key'                => $invoice->get_key(),
261
				'type'               => str_replace( 'wpi_', '', $invoice->post_type ),
262
				'mode'               => $invoice->mode,
263
				'user_ip'            => $invoice->get_ip(),
264
				'first_name'         => $invoice->get_first_name(),
265
				'last_name'          => $invoice->get_last_name(),
266
				'address'            => $invoice->get_address(),
267
				'city'               => $invoice->city,
268
				'state'              => $invoice->state,
269
				'country'            => $invoice->country,
270
				'zip'                => $invoice->zip,
271
				'adddress_confirmed' => (int) $invoice->adddress_confirmed,
272
				'gateway'            => $invoice->get_gateway(),
273
				'transaction_id'     => $invoice->get_transaction_id(),
274
				'currency'           => $invoice->get_currency(),
275
				'subtotal'           => $invoice->get_subtotal(),
276
				'tax'                => $invoice->get_tax(),
277
				'fees_total'         => $invoice->get_fees_total(),
278
				'total'              => $invoice->get_total(),
279
				'discount'           => $invoice->get_discount(),
280
				'discount_code'      => $invoice->get_discount_code(),
281
				'disable_taxes'      => $invoice->disable_taxes,
282
				'due_date'           => $invoice->get_due_date(),
283
				'completed_date'     => $invoice->get_completed_date(),
284
				'company'            => $invoice->company,
285
				'vat_number'         => $invoice->vat_number,
286
				'vat_rate'           => $invoice->vat_rate,
287
				'custom_meta'        => $invoice->payment_meta,
288
			);
289
290
			foreach ( $fields as $key => $val ) {
291
				if ( is_null( $val ) ) {
292
					$val = '';
293
				}
294
				$val = maybe_serialize( $val );
295
				$fields[ $key ] = $wpdb->prepare( '%s', $val );
296
			}
297
298
			$fields = implode( ', ', $fields );
299
			$invoice_rows[] = "($fields)";
300
301
			$item_rows    = array();
302
			$item_columns = array();
303
			foreach ( $invoice->get_cart_details() as $details ) {
304
				$fields = array(
305
					'post_id'          => $invoice->ID,
306
					'item_id'          => $details['id'],
307
					'item_name'        => $details['name'],
308
					'item_description' => empty( $details['meta']['description'] ) ? '' : $details['meta']['description'],
309
					'vat_rate'         => $details['vat_rate'],
310
					'vat_class'        => empty( $details['vat_class'] ) ? '_standard' : $details['vat_class'],
311
					'tax'              => $details['tax'],
312
					'item_price'       => $details['item_price'],
313
					'custom_price'     => $details['custom_price'],
314
					'quantity'         => $details['quantity'],
315
					'discount'         => $details['discount'],
316
					'subtotal'         => $details['subtotal'],
317
					'price'            => $details['price'],
318
					'meta'             => $details['meta'],
319
					'fees'             => $details['fees'],
320
				);
321
322
				$item_columns = array_keys( $fields );
323
324
				foreach ( $fields as $key => $val ) {
325
					if ( is_null( $val ) ) {
326
						$val = '';
327
					}
328
					$val = maybe_serialize( $val );
329
					$fields[ $key ] = $wpdb->prepare( '%s', $val );
330
				}
331
332
				$fields = implode( ', ', $fields );
333
				$item_rows[] = "($fields)";
334
			}
335
336
			$item_rows    = implode( ', ', $item_rows );
337
			$item_columns = implode( ', ', $item_columns );
338
			$wpdb->query( "INSERT INTO $invoice_items_table ($item_columns) VALUES $item_rows" );
339
		}
340
341
		if ( empty( $invoice_rows ) ) {
342
			return;
343
		}
344
345
		$invoice_rows = implode( ', ', $invoice_rows );
346
		$wpdb->query( "INSERT INTO $invoices_table VALUES $invoice_rows" );
347
348
	}
349
350
	/**
351
	 * Migrates old customers to new table.
352
	 *
353
	 */
354
	public static function migrate_old_customers() {
355
		global $wpdb;
356
357
		// Fetch post_id from $wpdb->prefix . 'getpaid_invoices' where customer_id = 0 or null.
358
		$invoice_ids = $wpdb->get_col( "SELECT post_id FROM {$wpdb->prefix}getpaid_invoices WHERE customer_id = 0 OR customer_id IS NULL" );
359
360
		foreach ( $invoice_ids as $invoice_id ) {
361
			$invoice = wpinv_get_invoice( $invoice_id );
362
363
			if ( empty( $invoice ) ) {
364
				continue;
365
			}
366
367
			// Fetch customer from the user ID.
368
			$user_id = $invoice->get_user_id();
369
370
			if ( empty( $user_id ) ) {
371
				continue;
372
			}
373
374
			$customer = getpaid_get_customer_by_user_id( $user_id );
375
376
			// Create if not exists.
377
			if ( empty( $customer ) ) {
378
				$customer = new GetPaid_Customer( 0 );
379
				$customer->clone_user( $user_id );
380
				$customer->save();
381
			}
382
383
			$invoice->set_customer_id( $customer->get_id() );
384
			$invoice->save();
385
		}
386
387
	}
388
389
	/**
390
	 * Migrates old invoices to new invoices.
391
	 *
392
	 */
393
	public static function rename_gateways_label() {
394
		global $wpdb;
395
396
		foreach ( array_keys( wpinv_get_payment_gateways() ) as $gateway ) {
397
398
			$wpdb->update(
399
				$wpdb->prefix . 'getpaid_invoices',
400
				array( 'gateway' => $gateway ),
401
				array( 'gateway' => wpinv_get_gateway_admin_label( $gateway ) ),
402
				'%s',
403
				'%s'
404
			);
405
406
		}
407
	}
408
409
	/**
410
	 * Returns the DB schema.
411
	 *
412
	 */
413
	public static function get_db_schema() {
414
		global $wpdb;
415
416
		if ( ! empty( self::$schema ) ) {
417
			return self::$schema;
418
		}
419
420
		require_once ABSPATH . 'wp-admin/includes/upgrade.php';
421
422
		$charset_collate = $wpdb->get_charset_collate();
423
424
		$schema = array();
425
426
		// Subscriptions.
427
		$schema['subscriptions'] = "CREATE TABLE {$wpdb->prefix}wpinv_subscriptions (
428
			id bigint(20) unsigned NOT NULL auto_increment,
429
			customer_id bigint(20) NOT NULL,
430
			frequency int(11) NOT NULL DEFAULT '1',
431
			period varchar(20) NOT NULL,
432
			initial_amount DECIMAL(16,4) NOT NULL,
433
			recurring_amount DECIMAL(16,4) NOT NULL,
434
			bill_times bigint(20) NOT NULL,
435
			transaction_id varchar(60) NOT NULL,
436
			parent_payment_id bigint(20) NOT NULL,
437
			product_id bigint(20) NOT NULL,
438
			created datetime NOT NULL,
439
			expiration datetime NOT NULL,
440
			trial_period varchar(20) NOT NULL,
441
			profile_id varchar(60) NOT NULL,
442
			status varchar(20) NOT NULL,
443
			PRIMARY KEY  (id),
444
			KEY profile_id (profile_id),
445
			KEY customer (customer_id),
446
			KEY transaction (transaction_id),
447
			KEY customer_and_status (customer_id, status)
448
		  ) $charset_collate;";
449
450
		// Invoices.
451
		$schema['invoices'] = "CREATE TABLE {$wpdb->prefix}getpaid_invoices (
452
			post_id BIGINT(20) NOT NULL,
453
			customer_id BIGINT(20) NOT NULL DEFAULT 0,
454
            `number` VARCHAR(100),
455
            invoice_key VARCHAR(100),
456
            `type` VARCHAR(100) NOT NULL DEFAULT 'invoice',
457
            mode VARCHAR(100) NOT NULL DEFAULT 'live',
458
            user_ip VARCHAR(100),
459
            first_name VARCHAR(100),
460
            last_name VARCHAR(100),
461
            `address` VARCHAR(100),
462
            city VARCHAR(100),
463
            `state` VARCHAR(100),
464
            country VARCHAR(100),
465
            zip VARCHAR(100),
466
            adddress_confirmed INT(10),
467
            gateway VARCHAR(100),
468
            transaction_id VARCHAR(100),
469
            currency VARCHAR(10),
470
            subtotal DECIMAL(16,4) NOT NULL DEFAULT 0,
471
            tax DECIMAL(16,4) NOT NULL DEFAULT 0,
472
            fees_total DECIMAL(16,4) NOT NULL DEFAULT 0,
473
            total DECIMAL(16,4) NOT NULL DEFAULT 0,
474
            discount DECIMAL(16,4) NOT NULL DEFAULT 0,
475
            discount_code VARCHAR(100),
476
            disable_taxes INT(2) NOT NULL DEFAULT 0,
477
            due_date DATETIME,
478
            completed_date DATETIME,
479
            company VARCHAR(100),
480
            vat_number VARCHAR(100),
481
            vat_rate VARCHAR(100),
482
            custom_meta TEXT,
483
			PRIMARY KEY  (post_id),
484
			KEY `number` (`number`),
485
			KEY invoice_key (invoice_key)
486
		  ) $charset_collate;";
487
488
		// Invoice items.
489
		$schema['items'] = "CREATE TABLE {$wpdb->prefix}getpaid_invoice_items (
490
			ID BIGINT(20) NOT NULL AUTO_INCREMENT,
491
            post_id BIGINT(20) NOT NULL,
492
            item_id BIGINT(20) NOT NULL,
493
            item_name TEXT NOT NULL,
494
            item_description TEXT NOT NULL,
495
            vat_rate FLOAT NOT NULL DEFAULT 0,
496
            vat_class VARCHAR(100),
497
            tax DECIMAL(16,4) NOT NULL DEFAULT 0,
498
            item_price DECIMAL(16,4) NOT NULL DEFAULT 0,
499
            custom_price DECIMAL(16,4) NOT NULL DEFAULT 0,
500
            quantity DECIMAL(16,4) NOT NULL DEFAULT 1,
501
            discount DECIMAL(16,4) NOT NULL DEFAULT 0,
502
            subtotal DECIMAL(16,4) NOT NULL DEFAULT 0,
503
            price DECIMAL(16,4) NOT NULL DEFAULT 0,
504
            meta TEXT,
505
            fees TEXT,
506
			PRIMARY KEY  (ID),
507
			KEY item_id (item_id),
508
			KEY post_id (post_id)
509
		  ) $charset_collate;";
510
511
		// Customers.
512
		$schema['customers'] = "CREATE TABLE {$wpdb->prefix}getpaid_customers (
513
			id BIGINT(20) NOT NULL AUTO_INCREMENT,
514
			user_id BIGINT(20) NOT NULL,
515
			email VARCHAR(100) NOT NULL,
516
			email_cc TEXT,
517
			status VARCHAR(100) NOT NULL DEFAULT 'active',
518
			purchase_value DECIMAL(18,9) NOT NULL DEFAULT 0,
519
			purchase_count BIGINT(20) NOT NULL DEFAULT 0,
520
			";
521
522
		// Add address fields.
523
		foreach ( array_keys( getpaid_user_address_fields( true ) ) as $field ) {
524
			// Skip id, user_id and email.
525
			if ( in_array( $field, array( 'id', 'user_id', 'email', 'purchase_value', 'purchase_count', 'date_created', 'date_modified', 'uuid' ), true ) ) {
526
				continue;
527
			}
528
529
			$field   = sanitize_key( $field );
530
			$length  = 100;
531
			$default = '';
532
533
			// Country.
534
			if ( 'country' === $field ) {
535
				$length  = 2;
536
				$default = wpinv_get_default_country();
537
			}
538
539
			// State.
540
			if ( 'state' === $field ) {
541
				$default = wpinv_get_default_state();
542
			}
543
544
			// Phone, zip.
545
			if ( in_array( $field, array( 'phone', 'zip' ), true ) ) {
546
				$length = 20;
547
			}
548
549
			$schema['customers'] .= "`$field` VARCHAR($length) NOT NULL DEFAULT '$default',
550
			";
551
		}
552
553
		$schema['customers'] .= "date_created DATETIME NOT NULL,
554
			date_modified DATETIME NOT NULL,
555
			uuid VARCHAR(100) NOT NULL,
556
			PRIMARY KEY  (id),
557
			KEY user_id (user_id),
558
			KEY email (email)
559
		  ) $charset_collate;";
560
561
		// Customer meta.
562
		$schema['customer_meta'] = "CREATE TABLE {$wpdb->prefix}getpaid_customer_meta (
563
			meta_id BIGINT(20) NOT NULL AUTO_INCREMENT,
564
			customer_id BIGINT(20) NOT NULL,
565
			meta_key VARCHAR(255) NOT NULL,
566
			meta_value LONGTEXT,
567
			PRIMARY KEY  (meta_id),
568
			KEY customer_id (customer_id),
569
			KEY meta_key (meta_key(191))
570
		  ) $charset_collate;";
571
572
		// Filter.
573
		$schema = apply_filters( 'getpaid_db_schema', $schema );
574
575
		self::$schema         = implode( "\n", array_values( $schema ) );
576
		self::$schema_version = md5( sanitize_key( self::$schema ) );
577
578
		return self::$schema;
579
	}
580
581
	/**
582
	 * Returns the DB schema version.
583
	 *
584
	 */
585
	public static function get_db_schema_version() {
586
		if ( ! empty( self::$schema_version ) ) {
587
			return self::$schema_version;
588
		}
589
590
		self::get_db_schema();
591
592
		return self::$schema_version;
593
	}
594
595
	/**
596
	 * Checks if the db schema is up to date.
597
	 *
598
	 * @return bool
599
	 */
600
	public static function is_db_schema_up_to_date() {
601
		return self::get_db_schema_version() === get_option( 'getpaid_db_schema' );
602
	}
603
604
	/**
605
	 * Set up the database tables which the plugin needs to function.
606
	 */
607
	public static function create_db_tables() {
608
		global $wpdb;
609
610
		$wpdb->hide_errors();
611
612
		require_once ABSPATH . 'wp-admin/includes/upgrade.php';
613
614
		$schema = self::get_db_schema();
615
616
		// If invoices table exists, rename key to invoice_key.
617
		$invoices_table = "{$wpdb->prefix}getpaid_invoices";
618
619
		if ( $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->prefix}getpaid_invoices'" ) === $invoices_table ) {
620
			$fields = $wpdb->get_results( "SHOW COLUMNS FROM {$wpdb->prefix}getpaid_invoices" );
621
622
			foreach ( $fields as $field ) {
623
				if ( 'key' === $field->Field ) {
624
					$wpdb->query( "ALTER TABLE {$wpdb->prefix}getpaid_invoices CHANGE `key` `invoice_key` VARCHAR(100)" );
625
					break;
626
				}
627
			}
628
		}
629
630
		dbDelta( $schema );
631
		wp_cache_flush();
632
		update_option( 'getpaid_db_schema', self::get_db_schema_version() );
633
	}
634
635
	/**
636
	 * Creates tables if schema is not up to date.
637
	 */
638
	public static function maybe_create_db_tables() {
639
		if ( ! self::is_db_schema_up_to_date() ) {
640
			self::create_db_tables();
641
		}
642
	}
643
}
644