Completed
Push — master ( 38a668...86a0ff )
by Mike
07:01
created

WC_Install   D

Complexity

Total Complexity 81

Size/Duplication

Total Lines 829
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 7

Importance

Changes 6
Bugs 1 Features 1
Metric Value
wmc 81
c 6
b 1
f 1
lcom 1
cbo 7
dl 0
loc 829
rs 4.4444

24 Methods

Rating   Name   Duplication   Size   Complexity  
A init() 0 9 1
A check_version() 0 6 3
A install_actions() 0 7 2
A updated_notice() 0 7 1
C install() 0 74 8
A update_wc_version() 0 4 1
A update_db_version() 0 4 2
A update() 0 16 4
A cron_schedules() 0 7 1
A create_cron_jobs() 0 21 3
B create_pages() 0 32 3
C create_options() 0 22 9
A create_terms() 0 18 4
B create_tables() 0 46 6
B get_schema() 0 170 3
B create_roles() 0 69 5
B get_core_capabilities() 0 38 2
B remove_roles() 0 23 5
B create_files() 0 40 6
A in_plugin_update_message() 0 14 4
B parse_update_notice() 0 24 4
A plugin_action_links() 0 7 1
A plugin_row_meta() 0 13 2
A wpmu_drop_tables() 0 15 1

How to fix   Complexity   

Complex Class

Complex classes like WC_Install often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use WC_Install, and based on these observations, apply Extract Interface, too.

1
<?php
1 ignored issue
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 18 and the first side effect is on line 12.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * Installation related functions and actions
4
 *
5
 * @author   WooThemes
6
 * @category Admin
7
 * @package  WooCommerce/Classes
8
 * @version  2.4.1
9
 */
10
11
if ( ! defined( 'ABSPATH' ) ) {
12
	exit;
13
}
14
15
/**
16
 * WC_Install Class.
17
 */
18
class WC_Install {
19
20
	/** @var array DB updates that need to be run */
21
	private static $db_updates = array(
22
		'2.0.0' => 'updates/woocommerce-update-2.0.php',
23
		'2.0.9' => 'updates/woocommerce-update-2.0.9.php',
24
		'2.1.0' => 'updates/woocommerce-update-2.1.php',
25
		'2.2.0' => 'updates/woocommerce-update-2.2.php',
26
		'2.3.0' => 'updates/woocommerce-update-2.3.php',
27
		'2.4.0' => 'updates/woocommerce-update-2.4.php',
28
		'2.4.1' => 'updates/woocommerce-update-2.4.1.php',
29
		'2.5.0' => 'updates/woocommerce-update-2.5.php',
30
		'2.6.0' => 'updates/woocommerce-update-2.6.php'
31
	);
32
33
	/**
34
	 * Hook in tabs.
35
	 */
36
	public static function init() {
37
		add_action( 'init', array( __CLASS__, 'check_version' ), 5 );
38
		add_action( 'admin_init', array( __CLASS__, 'install_actions' ) );
39
		add_action( 'in_plugin_update_message-woocommerce/woocommerce.php', array( __CLASS__, 'in_plugin_update_message' ) );
40
		add_filter( 'plugin_action_links_' . WC_PLUGIN_BASENAME, array( __CLASS__, 'plugin_action_links' ) );
41
		add_filter( 'plugin_row_meta', array( __CLASS__, 'plugin_row_meta' ), 10, 2 );
42
		add_filter( 'wpmu_drop_tables', array( __CLASS__, 'wpmu_drop_tables' ) );
43
		add_filter( 'cron_schedules', array( __CLASS__, 'cron_schedules' ) );
44
	}
45
46
	/**
47
	 * Check WooCommerce version and run the updater is required.
48
	 *
49
	 * This check is done on all requests and runs if he versions do not match.
50
	 */
51
	public static function check_version() {
52
		if ( ! defined( 'IFRAME_REQUEST' ) && get_option( 'woocommerce_version' ) !== WC()->version ) {
53
			self::install();
54
			do_action( 'woocommerce_updated' );
55
		}
56
	}
57
58
	/**
59
	 * Install actions when a update button is clicked within the admin area.
60
	 *
61
	 * This function is hooked into admin_init to affect admin only.
62
	 */
63
	public static function install_actions() {
64
		if ( ! empty( $_GET['do_update_woocommerce'] ) ) {
65
			self::update();
66
			WC_Admin_Notices::remove_notice( 'update' );
67
			add_action( 'admin_notices', array( __CLASS__, 'updated_notice' ) );
68
		}
69
	}
70
71
	/**
72
	 * Show notice stating update was successful.
73
	 */
74
	public static function updated_notice() {
75
		?>
76
		<div id="message" class="updated woocommerce-message wc-connect">
77
			<p><?php _e( 'WooCommerce data update complete. Thank you for updating to the latest version!', 'woocommerce' ); ?></p>
78
		</div>
79
		<?php
80
	}
81
82
	/**
83
	 * Install WC.
84
	 */
85
	public static function install() {
86
		global $wpdb;
87
88
		if ( ! defined( 'WC_INSTALLING' ) ) {
89
			define( 'WC_INSTALLING', true );
90
		}
91
92
		// Ensure needed classes are loaded
93
		include_once( 'admin/class-wc-admin-notices.php' );
94
95
		self::create_options();
96
		self::create_tables();
97
		self::create_roles();
98
99
		// Register post types
100
		WC_Post_types::register_post_types();
101
		WC_Post_types::register_taxonomies();
102
103
		// Also register endpoints - this needs to be done prior to rewrite rule flush
104
		WC()->query->init_query_vars();
105
		WC()->query->add_endpoints();
106
		WC_API::add_endpoint();
107
		WC_Auth::add_endpoint();
108
109
		self::create_terms();
110
		self::create_cron_jobs();
111
		self::create_files();
112
113
		// Queue upgrades/setup wizard
114
		$current_wc_version    = get_option( 'woocommerce_version', null );
115
		$current_db_version    = get_option( 'woocommerce_db_version', null );
116
		$major_wc_version      = substr( WC()->version, 0, strrpos( WC()->version, '.' ) );
0 ignored issues
show
Unused Code introduced by
$major_wc_version is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
117
118
		WC_Admin_Notices::remove_all_notices();
119
120
		// No versions? This is a new install :)
121
		if ( is_null( $current_wc_version ) && is_null( $current_db_version ) && apply_filters( 'woocommerce_enable_setup_wizard', true ) ) {
122
			WC_Admin_Notices::add_notice( 'install' );
123
			set_transient( '_wc_activation_redirect', 1, 30 );
124
125
		// No page? Let user run wizard again..
126
		} elseif ( ! get_option( 'woocommerce_cart_page_id' ) ) {
127
			WC_Admin_Notices::add_notice( 'install' );
128
		}
129
130
		if ( ! is_null( $current_db_version ) && version_compare( $current_db_version, max( array_keys( self::$db_updates ) ), '<' ) ) {
131
			WC_Admin_Notices::add_notice( 'update' );
132
		} else {
133
			self::update_db_version();
134
		}
135
136
		self::update_wc_version();
137
138
		// Flush rules after install
139
		flush_rewrite_rules();
140
		delete_transient( 'wc_attribute_taxonomies' );
141
142
		/*
143
		 * Deletes all expired transients. The multi-table delete syntax is used.
144
		 * to delete the transient record from table a, and the corresponding.
145
		 * transient_timeout record from table b.
146
		 *
147
		 * Based on code inside core's upgrade_network() function.
148
		 */
149
		$sql = "DELETE a, b FROM $wpdb->options a, $wpdb->options b
150
			WHERE a.option_name LIKE %s
151
			AND a.option_name NOT LIKE %s
152
			AND b.option_name = CONCAT( '_transient_timeout_', SUBSTRING( a.option_name, 12 ) )
153
			AND b.option_value < %d";
154
		$wpdb->query( $wpdb->prepare( $sql, $wpdb->esc_like( '_transient_' ) . '%', $wpdb->esc_like( '_transient_timeout_' ) . '%', time() ) );
155
156
		// Trigger action
157
		do_action( 'woocommerce_installed' );
158
	}
159
160
	/**
161
	 * Update WC version to current.
162
	 */
163
	private static function update_wc_version() {
164
		delete_option( 'woocommerce_version' );
165
		add_option( 'woocommerce_version', WC()->version );
166
	}
167
168
	/**
169
	 * Update DB version to current.
170
	 */
171
	private static function update_db_version( $version = null ) {
172
		delete_option( 'woocommerce_db_version' );
173
		add_option( 'woocommerce_db_version', is_null( $version ) ? WC()->version : $version );
174
	}
175
176
	/**
177
	 * Handle updates.
178
	 */
179
	private static function update() {
180
		if ( ! defined( 'WC_UPDATING' ) ) {
181
			define( 'WC_UPDATING', true );
182
		}
183
184
		$current_db_version = get_option( 'woocommerce_db_version' );
185
186
		foreach ( self::$db_updates as $version => $updater ) {
187
			if ( version_compare( $current_db_version, $version, '<' ) ) {
188
				include( $updater );
189
				self::update_db_version( $version );
190
			}
191
		}
192
193
		self::update_db_version();
194
	}
195
196
	/**
197
	 * Add more cron schedules.
198
	 * @param  array $schedules
199
	 * @return array
200
	 */
201
	public static function cron_schedules( $schedules ) {
202
		$schedules['monthly'] = array(
203
			'interval' => 2635200,
204
			'display'  => __( 'Monthly', 'woocommerce' )
205
		);
206
		return $schedules;
207
	}
208
209
	/**
210
	 * Create cron jobs (clear them first).
211
	 */
212
	private static function create_cron_jobs() {
213
		wp_clear_scheduled_hook( 'woocommerce_scheduled_sales' );
214
		wp_clear_scheduled_hook( 'woocommerce_cancel_unpaid_orders' );
215
		wp_clear_scheduled_hook( 'woocommerce_cleanup_sessions' );
216
		wp_clear_scheduled_hook( 'woocommerce_geoip_updater' );
217
		wp_clear_scheduled_hook( 'woocommerce_tracker_send_event' );
218
219
		$ve = get_option( 'gmt_offset' ) > 0 ? '+' : '-';
220
221
		wp_schedule_event( strtotime( '00:00 tomorrow ' . $ve . get_option( 'gmt_offset' ) . ' HOURS' ), 'daily', 'woocommerce_scheduled_sales' );
222
223
		$held_duration = get_option( 'woocommerce_hold_stock_minutes', '60' );
224
225
		if ( $held_duration != '' ) {
226
			wp_schedule_single_event( time() + ( absint( $held_duration ) * 60 ), 'woocommerce_cancel_unpaid_orders' );
227
		}
228
229
		wp_schedule_event( time(), 'twicedaily', 'woocommerce_cleanup_sessions' );
230
		wp_schedule_event( strtotime( 'first tuesday of next month' ), 'monthly', 'woocommerce_geoip_updater' );
231
		wp_schedule_event( time(), apply_filters( 'woocommerce_tracker_event_recurrence', 'daily' ), 'woocommerce_tracker_send_event' );
232
	}
233
234
	/**
235
	 * Create pages that the plugin relies on, storing page id's in variables.
236
	 */
237
	public static function create_pages() {
238
		include_once( 'admin/wc-admin-functions.php' );
239
240
		$pages = apply_filters( 'woocommerce_create_pages', array(
241
			'shop' => array(
242
				'name'    => _x( 'shop', 'Page slug', 'woocommerce' ),
243
				'title'   => _x( 'Shop', 'Page title', 'woocommerce' ),
244
				'content' => ''
245
			),
246
			'cart' => array(
247
				'name'    => _x( 'cart', 'Page slug', 'woocommerce' ),
248
				'title'   => _x( 'Cart', 'Page title', 'woocommerce' ),
249
				'content' => '[' . apply_filters( 'woocommerce_cart_shortcode_tag', 'woocommerce_cart' ) . ']'
250
			),
251
			'checkout' => array(
252
				'name'    => _x( 'checkout', 'Page slug', 'woocommerce' ),
253
				'title'   => _x( 'Checkout', 'Page title', 'woocommerce' ),
254
				'content' => '[' . apply_filters( 'woocommerce_checkout_shortcode_tag', 'woocommerce_checkout' ) . ']'
255
			),
256
			'myaccount' => array(
257
				'name'    => _x( 'my-account', 'Page slug', 'woocommerce' ),
258
				'title'   => _x( 'My Account', 'Page title', 'woocommerce' ),
259
				'content' => '[' . apply_filters( 'woocommerce_my_account_shortcode_tag', 'woocommerce_my_account' ) . ']'
260
			)
261
		) );
262
263
		foreach ( $pages as $key => $page ) {
264
			wc_create_page( esc_sql( $page['name'] ), 'woocommerce_' . $key . '_page_id', $page['title'], $page['content'], ! empty( $page['parent'] ) ? wc_get_page_id( $page['parent'] ) : '' );
265
		}
266
267
		delete_transient( 'woocommerce_cache_excluded_uris' );
268
	}
269
270
	/**
271
	 * Default options.
272
	 *
273
	 * Sets up the default options used on the settings page.
274
	 */
275
	private static function create_options() {
276
		// Include settings so that we can run through defaults
277
		include_once( 'admin/class-wc-admin-settings.php' );
278
279
		$settings = WC_Admin_Settings::get_settings_pages();
280
281
		foreach ( $settings as $section ) {
282
			if ( ! method_exists( $section, 'get_settings' ) ) {
283
				continue;
284
			}
285
			$subsections = array_unique( array_merge( array( '' ), array_keys( $section->get_sections() ) ) );
286
287
			foreach ( $subsections as $subsection ) {
288
				foreach ( $section->get_settings( $subsection ) as $value ) {
289
					if ( isset( $value['default'] ) && isset( $value['id'] ) ) {
290
						$autoload = isset( $value['autoload'] ) ? (bool) $value['autoload'] : true;
291
						add_option( $value['id'], $value['default'], '', ( $autoload ? 'yes' : 'no' ) );
292
					}
293
				}
294
			}
295
		}
296
	}
297
298
	/**
299
	 * Add the default terms for WC taxonomies - product types and order statuses. Modify this at your own risk.
300
	 */
301
	private static function create_terms() {
302
		$taxonomies = array(
303
			'product_type' => array(
304
				'simple',
305
				'grouped',
306
				'variable',
307
				'external'
308
			)
309
		);
310
311
		foreach ( $taxonomies as $taxonomy => $terms ) {
312
			foreach ( $terms as $term ) {
313
				if ( ! get_term_by( 'slug', sanitize_title( $term ), $taxonomy ) ) {
314
					wp_insert_term( $term, $taxonomy );
315
				}
316
			}
317
		}
318
	}
319
320
	/**
321
	 * Set up the database tables which the plugin needs to function.
322
	 *
323
	 * Tables:
324
	 *		woocommerce_attribute_taxonomies - Table for storing attribute taxonomies - these are user defined
325
	 *		woocommerce_termmeta - Term meta table - sadly WordPress does not have termmeta so we need our own
326
	 *		woocommerce_downloadable_product_permissions - Table for storing user and guest download permissions.
327
	 *			KEY(order_id, product_id, download_id) used for organizing downloads on the My Account page
328
	 *		woocommerce_order_items - Order line items are stored in a table to make them easily queryable for reports
329
	 *		woocommerce_order_itemmeta - Order line item meta is stored in a table for storing extra data.
330
	 *		woocommerce_tax_rates - Tax Rates are stored inside 2 tables making tax queries simple and efficient.
331
	 *		woocommerce_tax_rate_locations - Each rate can be applied to more than one postcode/city hence the second table.
332
	 */
333
	private static function create_tables() {
334
		global $wpdb;
335
336
		$wpdb->hide_errors();
337
338
		require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
339
340
		/**
341
		 * Before updating with DBDELTA, remove any primary keys which could be
342
		 * modified due to schema updates.
343
		 */
344
		if ( $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->prefix}woocommerce_downloadable_product_permissions';" ) ) {
345
			if ( ! $wpdb->get_var( "SHOW COLUMNS FROM `{$wpdb->prefix}woocommerce_downloadable_product_permissions` LIKE 'permission_id';" ) ) {
346
				$wpdb->query( "ALTER TABLE {$wpdb->prefix}woocommerce_downloadable_product_permissions DROP PRIMARY KEY, ADD `permission_id` bigint(20) NOT NULL PRIMARY KEY AUTO_INCREMENT;" );
347
			}
348
		}
349
350
		/**
351
		 * Before updating with DBDELTA, drop existing indexes so they can be
352
		 * re-added without duplicate key errors. Index lengths were added
353
		 * in 2.5.3.
354
		 */
355
		$indexes_to_remove = array(
356
			'woocommerce_attribute_taxonomies'             => 'attribute_name',
357
			'woocommerce_termmeta'                         => 'meta_key',
358
			'woocommerce_downloadable_product_permissions' => 'download_order_key_product',
359
			'woocommerce_order_itemmeta'                   => 'meta_key',
360
			'woocommerce_tax_rates'                        => 'tax_rate_country',
361
			'woocommerce_tax_rates'                        => 'tax_rate_state',
362
			'woocommerce_tax_rates'                        => 'tax_rate_class',
363
			'woocommerce_tax_rate_locations'               => 'location_type_code',
364
			'woocommerce_shipping_zone_locations'          => 'location_type_code',
365
		);
366
367
		foreach ( $indexes_to_remove as $table => $key ) {
368
			$table = esc_sql( $wpdb->prefix . $table );
369
			$key   = esc_sql( $key );
370
			if ( $wpdb->get_var( "SHOW TABLES LIKE '{$table}';" ) ) {
371
				if ( $wpdb->get_var( "SHOW INDEX FROM {$table} WHERE KEY_NAME = '{$key}';" ) ) {
372
					$wpdb->query(  "ALTER TABLE {$table} DROP INDEX `{$key}`;" );
373
				}
374
			}
375
		}
376
377
		dbDelta( self::get_schema() );
378
	}
379
380
	/**
381
	 * Get Table schema.
382
	 * @return string
383
	 */
384
	private static function get_schema() {
385
		global $wpdb;
386
387
		$collate = '';
388
389
		if ( $wpdb->has_cap( 'collation' ) ) {
390
			$collate = $wpdb->get_charset_collate();
391
		}
392
393
		/*
394
		 * Indexes have a maximum size of 767 bytes. Historically, we haven't need to be concerned about that.
395
		 * As of WordPress 4.2, however, we moved to utf8mb4, which uses 4 bytes per character. This means that an index which
396
		 * used to have room for floor(767/3) = 255 characters, now only has room for floor(767/4) = 191 characters.
397
		 */
398
		$max_index_length = 191;
399
400
		$tables = "
401
CREATE TABLE {$wpdb->prefix}woocommerce_sessions (
402
  session_id bigint(20) NOT NULL AUTO_INCREMENT,
403
  session_key char(32) NOT NULL,
404
  session_value longtext NOT NULL,
405
  session_expiry bigint(20) NOT NULL,
406
  UNIQUE KEY session_id (session_id),
407
  PRIMARY KEY  (session_key)
408
) $collate;
409
CREATE TABLE {$wpdb->prefix}woocommerce_api_keys (
410
  key_id bigint(20) NOT NULL auto_increment,
411
  user_id bigint(20) NOT NULL,
412
  description longtext NULL,
413
  permissions varchar(10) NOT NULL,
414
  consumer_key char(64) NOT NULL,
415
  consumer_secret char(43) NOT NULL,
416
  nonces longtext NULL,
417
  truncated_key char(7) NOT NULL,
418
  last_access datetime NULL default null,
419
  PRIMARY KEY  (key_id),
420
  KEY consumer_key (consumer_key),
421
  KEY consumer_secret (consumer_secret)
422
) $collate;
423
CREATE TABLE {$wpdb->prefix}woocommerce_attribute_taxonomies (
424
  attribute_id bigint(20) NOT NULL auto_increment,
425
  attribute_name varchar(200) NOT NULL,
426
  attribute_label longtext NULL,
427
  attribute_type varchar(200) NOT NULL,
428
  attribute_orderby varchar(200) NOT NULL,
429
  attribute_public int(1) NOT NULL DEFAULT 1,
430
  PRIMARY KEY  (attribute_id),
431
  KEY attribute_name (attribute_name($max_index_length))
432
) $collate;
433
CREATE TABLE {$wpdb->prefix}woocommerce_downloadable_product_permissions (
434
  permission_id bigint(20) NOT NULL auto_increment,
435
  download_id varchar(32) NOT NULL,
436
  product_id bigint(20) NOT NULL,
437
  order_id bigint(20) NOT NULL DEFAULT 0,
438
  order_key varchar(200) NOT NULL,
439
  user_email varchar(200) NOT NULL,
440
  user_id bigint(20) NULL,
441
  downloads_remaining varchar(9) NULL,
442
  access_granted datetime NOT NULL default '0000-00-00 00:00:00',
443
  access_expires datetime NULL default null,
444
  download_count bigint(20) NOT NULL DEFAULT 0,
445
  PRIMARY KEY  (permission_id),
446
  KEY download_order_key_product (product_id,order_id,order_key($max_index_length),download_id),
447
  KEY download_order_product (download_id,order_id,product_id)
448
) $collate;
449
CREATE TABLE {$wpdb->prefix}woocommerce_order_items (
450
  order_item_id bigint(20) NOT NULL auto_increment,
451
  order_item_name longtext NOT NULL,
452
  order_item_type varchar(200) NOT NULL DEFAULT '',
453
  order_id bigint(20) NOT NULL,
454
  PRIMARY KEY  (order_item_id),
455
  KEY order_id (order_id)
456
) $collate;
457
CREATE TABLE {$wpdb->prefix}woocommerce_order_itemmeta (
458
  meta_id bigint(20) NOT NULL auto_increment,
459
  order_item_id bigint(20) NOT NULL,
460
  meta_key varchar(255) default NULL,
461
  meta_value longtext NULL,
462
  PRIMARY KEY  (meta_id),
463
  KEY order_item_id (order_item_id),
464
  KEY meta_key (meta_key($max_index_length))
465
) $collate;
466
CREATE TABLE {$wpdb->prefix}woocommerce_tax_rates (
467
  tax_rate_id bigint(20) NOT NULL auto_increment,
468
  tax_rate_country varchar(200) NOT NULL DEFAULT '',
469
  tax_rate_state varchar(200) NOT NULL DEFAULT '',
470
  tax_rate varchar(200) NOT NULL DEFAULT '',
471
  tax_rate_name varchar(200) NOT NULL DEFAULT '',
472
  tax_rate_priority bigint(20) NOT NULL,
473
  tax_rate_compound int(1) NOT NULL DEFAULT 0,
474
  tax_rate_shipping int(1) NOT NULL DEFAULT 1,
475
  tax_rate_order bigint(20) NOT NULL,
476
  tax_rate_class varchar(200) NOT NULL DEFAULT '',
477
  PRIMARY KEY  (tax_rate_id),
478
  KEY tax_rate_country (tax_rate_country($max_index_length)),
479
  KEY tax_rate_state (tax_rate_state($max_index_length)),
480
  KEY tax_rate_class (tax_rate_class($max_index_length)),
481
  KEY tax_rate_priority (tax_rate_priority)
482
) $collate;
483
CREATE TABLE {$wpdb->prefix}woocommerce_tax_rate_locations (
484
  location_id bigint(20) NOT NULL auto_increment,
485
  location_code varchar(255) NOT NULL,
486
  tax_rate_id bigint(20) NOT NULL,
487
  location_type varchar(40) NOT NULL,
488
  PRIMARY KEY  (location_id),
489
  KEY tax_rate_id (tax_rate_id),
490
  KEY location_type (location_type),
491
  KEY location_type_code (location_type(40),location_code(90))
492
) $collate;
493
CREATE TABLE {$wpdb->prefix}woocommerce_shipping_zones (
494
  zone_id bigint(20) NOT NULL auto_increment,
495
  zone_name varchar(255) NOT NULL,
496
  zone_order bigint(20) NOT NULL,
497
  PRIMARY KEY  (zone_id)
498
) $collate;
499
CREATE TABLE {$wpdb->prefix}woocommerce_shipping_zone_locations (
500
  location_id bigint(20) NOT NULL auto_increment,
501
  zone_id bigint(20) NOT NULL,
502
  location_code varchar(255) NOT NULL,
503
  location_type varchar(40) NOT NULL,
504
  PRIMARY KEY  (location_id),
505
  KEY location_id (location_id),
506
  KEY location_type (location_type),
507
  KEY location_type_code (location_type(40),location_code(90))
508
) $collate;
509
CREATE TABLE {$wpdb->prefix}woocommerce_shipping_zone_methods (
510
  zone_id bigint(20) NOT NULL,
511
  instance_id bigint(20) NOT NULL auto_increment,
512
  method_id varchar(255) NOT NULL,
513
  method_order bigint(20) NOT NULL,
514
  PRIMARY KEY  (instance_id)
515
) $collate;
516
CREATE TABLE {$wpdb->prefix}woocommerce_payment_tokens (
517
  token_id bigint(20) NOT NULL auto_increment,
518
  gateway_id varchar(255) NOT NULL,
519
  token text NOT NULL,
520
  user_id bigint(20) NOT NULL DEFAULT '0',
521
  type varchar(255) NOT NULL,
522
  is_default tinyint(1) NOT NULL DEFAULT '0',
523
  PRIMARY KEY  (token_id),
524
  KEY user_id (user_id)
525
) $collate;
526
CREATE TABLE {$wpdb->prefix}woocommerce_payment_tokenmeta (
527
  meta_id bigint(20) NOT NULL auto_increment,
528
  payment_token_id bigint(20) NOT NULL,
529
  meta_key varchar(255) NULL,
530
  meta_value longtext NULL,
531
  PRIMARY KEY  (meta_id),
532
  KEY payment_token_id (payment_token_id),
533
  KEY meta_key (meta_key)
534
) $collate;
535
		";
536
537
		// Term meta is only needed for old installs.
538
		if ( ! function_exists( 'get_term_meta' ) ) {
539
			$tables .= "
540
CREATE TABLE {$wpdb->prefix}woocommerce_termmeta (
541
  meta_id bigint(20) NOT NULL auto_increment,
542
  woocommerce_term_id bigint(20) NOT NULL,
543
  meta_key varchar(255) default NULL,
544
  meta_value longtext NULL,
545
  PRIMARY KEY  (meta_id),
546
  KEY woocommerce_term_id (woocommerce_term_id),
547
  KEY meta_key (meta_key($max_index_length))
548
) $collate;
549
			";
550
		}
551
552
		return $tables;
553
	}
554
555
	/**
556
	 * Create roles and capabilities.
557
	 */
558
	public static function create_roles() {
559
		global $wp_roles;
560
561
		if ( ! class_exists( 'WP_Roles' ) ) {
562
			return;
563
		}
564
565
		if ( ! isset( $wp_roles ) ) {
566
			$wp_roles = new WP_Roles();
567
		}
568
569
		// Customer role
570
		add_role( 'customer', __( 'Customer', 'woocommerce' ), array(
571
			'read' 					=> true
572
		) );
573
574
		// Shop manager role
575
		add_role( 'shop_manager', __( 'Shop Manager', 'woocommerce' ), array(
576
			'level_9'                => true,
577
			'level_8'                => true,
578
			'level_7'                => true,
579
			'level_6'                => true,
580
			'level_5'                => true,
581
			'level_4'                => true,
582
			'level_3'                => true,
583
			'level_2'                => true,
584
			'level_1'                => true,
585
			'level_0'                => true,
586
			'read'                   => true,
587
			'read_private_pages'     => true,
588
			'read_private_posts'     => true,
589
			'edit_users'             => true,
590
			'edit_posts'             => true,
591
			'edit_pages'             => true,
592
			'edit_published_posts'   => true,
593
			'edit_published_pages'   => true,
594
			'edit_private_pages'     => true,
595
			'edit_private_posts'     => true,
596
			'edit_others_posts'      => true,
597
			'edit_others_pages'      => true,
598
			'publish_posts'          => true,
599
			'publish_pages'          => true,
600
			'delete_posts'           => true,
601
			'delete_pages'           => true,
602
			'delete_private_pages'   => true,
603
			'delete_private_posts'   => true,
604
			'delete_published_pages' => true,
605
			'delete_published_posts' => true,
606
			'delete_others_posts'    => true,
607
			'delete_others_pages'    => true,
608
			'manage_categories'      => true,
609
			'manage_links'           => true,
610
			'moderate_comments'      => true,
611
			'unfiltered_html'        => true,
612
			'upload_files'           => true,
613
			'export'                 => true,
614
			'import'                 => true,
615
			'list_users'             => true
616
		) );
617
618
		$capabilities = self::get_core_capabilities();
619
620
		foreach ( $capabilities as $cap_group ) {
621
			foreach ( $cap_group as $cap ) {
622
				$wp_roles->add_cap( 'shop_manager', $cap );
623
				$wp_roles->add_cap( 'administrator', $cap );
624
			}
625
		}
626
	}
627
628
	/**
629
	 * Get capabilities for WooCommerce - these are assigned to admin/shop manager during installation or reset.
630
	 *
631
	 * @return array
632
	 */
633
	 private static function get_core_capabilities() {
634
		$capabilities = array();
635
636
		$capabilities['core'] = array(
637
			'manage_woocommerce',
638
			'view_woocommerce_reports'
639
		);
640
641
		$capability_types = array( 'product', 'shop_order', 'shop_coupon', 'shop_webhook' );
642
643
		foreach ( $capability_types as $capability_type ) {
644
645
			$capabilities[ $capability_type ] = array(
646
				// Post type
647
				"edit_{$capability_type}",
648
				"read_{$capability_type}",
649
				"delete_{$capability_type}",
650
				"edit_{$capability_type}s",
651
				"edit_others_{$capability_type}s",
652
				"publish_{$capability_type}s",
653
				"read_private_{$capability_type}s",
654
				"delete_{$capability_type}s",
655
				"delete_private_{$capability_type}s",
656
				"delete_published_{$capability_type}s",
657
				"delete_others_{$capability_type}s",
658
				"edit_private_{$capability_type}s",
659
				"edit_published_{$capability_type}s",
660
661
				// Terms
662
				"manage_{$capability_type}_terms",
663
				"edit_{$capability_type}_terms",
664
				"delete_{$capability_type}_terms",
665
				"assign_{$capability_type}_terms"
666
			);
667
		}
668
669
		return $capabilities;
670
	}
671
672
	/**
673
	 * woocommerce_remove_roles function.
674
	 */
675
	public static function remove_roles() {
676
		global $wp_roles;
677
678
		if ( ! class_exists( 'WP_Roles' ) ) {
679
			return;
680
		}
681
682
		if ( ! isset( $wp_roles ) ) {
683
			$wp_roles = new WP_Roles();
684
		}
685
686
		$capabilities = self::get_core_capabilities();
687
688
		foreach ( $capabilities as $cap_group ) {
689
			foreach ( $cap_group as $cap ) {
690
				$wp_roles->remove_cap( 'shop_manager', $cap );
691
				$wp_roles->remove_cap( 'administrator', $cap );
692
			}
693
		}
694
695
		remove_role( 'customer' );
696
		remove_role( 'shop_manager' );
697
	}
698
699
	/**
700
	 * Create files/directories.
701
	 */
702
	private static function create_files() {
703
		// Install files and folders for uploading files and prevent hotlinking
704
		$upload_dir      = wp_upload_dir();
705
		$download_method = get_option( 'woocommerce_file_download_method', 'force' );
706
707
		$files = array(
708
			array(
709
				'base' 		=> $upload_dir['basedir'] . '/woocommerce_uploads',
710
				'file' 		=> 'index.html',
711
				'content' 	=> ''
712
			),
713
			array(
714
				'base' 		=> WC_LOG_DIR,
715
				'file' 		=> '.htaccess',
716
				'content' 	=> 'deny from all'
717
			),
718
			array(
719
				'base' 		=> WC_LOG_DIR,
720
				'file' 		=> 'index.html',
721
				'content' 	=> ''
722
			)
723
		);
724
725
		if ( 'redirect' !== $download_method ) {
726
			$files[] = array(
727
				'base' 		=> $upload_dir['basedir'] . '/woocommerce_uploads',
728
				'file' 		=> '.htaccess',
729
				'content' 	=> 'deny from all'
730
			);
731
		}
732
733
		foreach ( $files as $file ) {
734
			if ( wp_mkdir_p( $file['base'] ) && ! file_exists( trailingslashit( $file['base'] ) . $file['file'] ) ) {
735
				if ( $file_handle = @fopen( trailingslashit( $file['base'] ) . $file['file'], 'w' ) ) {
736
					fwrite( $file_handle, $file['content'] );
737
					fclose( $file_handle );
738
				}
739
			}
740
		}
741
	}
742
743
	/**
744
	 * Show plugin changes. Code adapted from W3 Total Cache.
745
	 */
746
	public static function in_plugin_update_message( $args ) {
747
		$transient_name = 'wc_upgrade_notice_' . $args['Version'];
748
749
		if ( false === ( $upgrade_notice = get_transient( $transient_name ) ) ) {
750
			$response = wp_safe_remote_get( 'https://plugins.svn.wordpress.org/woocommerce/trunk/readme.txt' );
751
752
			if ( ! is_wp_error( $response ) && ! empty( $response['body'] ) ) {
753
				$upgrade_notice = self::parse_update_notice( $response['body'] );
754
				set_transient( $transient_name, $upgrade_notice, DAY_IN_SECONDS );
755
			}
756
		}
757
758
		echo wp_kses_post( $upgrade_notice );
759
	}
760
761
	/**
762
	 * Parse update notice from readme file.
763
	 * @param  string $content
764
	 * @return string
765
	 */
766
	private static function parse_update_notice( $content ) {
767
		// Output Upgrade Notice
768
		$matches        = null;
769
		$regexp         = '~==\s*Upgrade Notice\s*==\s*=\s*(.*)\s*=(.*)(=\s*' . preg_quote( WC_VERSION ) . '\s*=|$)~Uis';
770
		$upgrade_notice = '';
771
772
		if ( preg_match( $regexp, $content, $matches ) ) {
773
			$version = trim( $matches[1] );
774
			$notices = (array) preg_split('~[\r\n]+~', trim( $matches[2] ) );
775
776
			if ( version_compare( WC_VERSION, $version, '<' ) ) {
777
778
				$upgrade_notice .= '<div class="wc_plugin_upgrade_notice">';
779
780
				foreach ( $notices as $index => $line ) {
781
					$upgrade_notice .= wp_kses_post( preg_replace( '~\[([^\]]*)\]\(([^\)]*)\)~', '<a href="${2}">${1}</a>', $line ) );
782
				}
783
784
				$upgrade_notice .= '</div> ';
785
			}
786
		}
787
788
		return wp_kses_post( $upgrade_notice );
789
	}
790
791
	/**
792
	 * Show action links on the plugin screen.
793
	 *
794
	 * @param	mixed $links Plugin Action links
795
	 * @return	array
796
	 */
797
	public static function plugin_action_links( $links ) {
798
		$action_links = array(
799
			'settings' => '<a href="' . admin_url( 'admin.php?page=wc-settings' ) . '" title="' . esc_attr( __( 'View WooCommerce Settings', 'woocommerce' ) ) . '">' . __( 'Settings', 'woocommerce' ) . '</a>',
800
		);
801
802
		return array_merge( $action_links, $links );
803
	}
804
805
	/**
806
	 * Show row meta on the plugin screen.
807
	 *
808
	 * @param	mixed $links Plugin Row Meta
809
	 * @param	mixed $file  Plugin Base file
810
	 * @return	array
811
	 */
812
	public static function plugin_row_meta( $links, $file ) {
813
		if ( $file == WC_PLUGIN_BASENAME ) {
814
			$row_meta = array(
815
				'docs'    => '<a href="' . esc_url( apply_filters( 'woocommerce_docs_url', 'http://docs.woothemes.com/documentation/plugins/woocommerce/' ) ) . '" title="' . esc_attr( __( 'View WooCommerce Documentation', 'woocommerce' ) ) . '">' . __( 'Docs', 'woocommerce' ) . '</a>',
816
				'apidocs' => '<a href="' . esc_url( apply_filters( 'woocommerce_apidocs_url', 'http://docs.woothemes.com/wc-apidocs/' ) ) . '" title="' . esc_attr( __( 'View WooCommerce API Docs', 'woocommerce' ) ) . '">' . __( 'API Docs', 'woocommerce' ) . '</a>',
817
				'support' => '<a href="' . esc_url( apply_filters( 'woocommerce_support_url', 'http://support.woothemes.com/' ) ) . '" title="' . esc_attr( __( 'Visit Premium Customer Support Forum', 'woocommerce' ) ) . '">' . __( 'Premium Support', 'woocommerce' ) . '</a>',
818
			);
819
820
			return array_merge( $links, $row_meta );
821
		}
822
823
		return (array) $links;
824
	}
825
826
	/**
827
	 * Uninstall tables when MU blog is deleted.
828
	 * @param  array $tables
829
	 * @return string[]
830
	 */
831
	public static function wpmu_drop_tables( $tables ) {
832
		global $wpdb;
833
834
		$tables[] = $wpdb->prefix . 'woocommerce_sessions';
835
		$tables[] = $wpdb->prefix . 'woocommerce_api_keys';
836
		$tables[] = $wpdb->prefix . 'woocommerce_attribute_taxonomies';
837
		$tables[] = $wpdb->prefix . 'woocommerce_downloadable_product_permissions';
838
		$tables[] = $wpdb->prefix . 'woocommerce_termmeta';
839
		$tables[] = $wpdb->prefix . 'woocommerce_tax_rates';
840
		$tables[] = $wpdb->prefix . 'woocommerce_tax_rate_locations';
841
		$tables[] = $wpdb->prefix . 'woocommerce_order_items';
842
		$tables[] = $wpdb->prefix . 'woocommerce_order_itemmeta';
843
844
		return $tables;
845
	}
846
}
847
848
WC_Install::init();
849