Passed
Push — master ( 345b42...86cae5 )
by Brian
05:49
created

GetPaid_Installer::upgrade_db()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 31
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

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