Completed
Push — master ( 7e712e...5e88ad )
by Mike
09:12
created

WC_Install::install_actions()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 7
Code Lines 5

Duplication

Lines 0
Ratio 0 %
Metric Value
dl 0
loc 7
rs 9.4285
cc 2
eloc 5
nc 2
nop 0
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
		dbDelta( self::get_schema() );
351
	}
352
353
	/**
354
	 * Get Table schema.
355
	 * @return string
356
	 */
357
	private static function get_schema() {
358
		global $wpdb;
359
360
		$collate = '';
361
362
		if ( $wpdb->has_cap( 'collation' ) ) {
363
			$collate = $wpdb->get_charset_collate();
364
		}
365
366
		/*
367
		 * Indexes have a maximum size of 767 bytes. Historically, we haven't need to be concerned about that.
368
		 * As of WordPress 4.2, however, we moved to utf8mb4, which uses 4 bytes per character. This means that an index which
369
		 * used to have room for floor(767/3) = 255 characters, now only has room for floor(767/4) = 191 characters.
370
		 *
371
		 * This may cause duplicate index notices in logs due to https://core.trac.wordpress.org/ticket/34870 but dropping
372
		 * indexes first causes too much load on some servers/larger DB.
373
		 */
374
		$max_index_length = 191;
375
376
		$tables = "
377
CREATE TABLE {$wpdb->prefix}woocommerce_sessions (
378
  session_id bigint(20) NOT NULL AUTO_INCREMENT,
379
  session_key char(32) NOT NULL,
380
  session_value longtext NOT NULL,
381
  session_expiry bigint(20) NOT NULL,
382
  UNIQUE KEY session_id (session_id),
383
  PRIMARY KEY  (session_key)
384
) $collate;
385
CREATE TABLE {$wpdb->prefix}woocommerce_api_keys (
386
  key_id bigint(20) NOT NULL auto_increment,
387
  user_id bigint(20) NOT NULL,
388
  description longtext NULL,
389
  permissions varchar(10) NOT NULL,
390
  consumer_key char(64) NOT NULL,
391
  consumer_secret char(43) NOT NULL,
392
  nonces longtext NULL,
393
  truncated_key char(7) NOT NULL,
394
  last_access datetime NULL default null,
395
  PRIMARY KEY  (key_id),
396
  KEY consumer_key (consumer_key),
397
  KEY consumer_secret (consumer_secret)
398
) $collate;
399
CREATE TABLE {$wpdb->prefix}woocommerce_attribute_taxonomies (
400
  attribute_id bigint(20) NOT NULL auto_increment,
401
  attribute_name varchar(200) NOT NULL,
402
  attribute_label longtext NULL,
403
  attribute_type varchar(200) NOT NULL,
404
  attribute_orderby varchar(200) NOT NULL,
405
  attribute_public int(1) NOT NULL DEFAULT 1,
406
  PRIMARY KEY  (attribute_id),
407
  KEY attribute_name (attribute_name($max_index_length))
408
) $collate;
409
CREATE TABLE {$wpdb->prefix}woocommerce_downloadable_product_permissions (
410
  permission_id bigint(20) NOT NULL auto_increment,
411
  download_id varchar(32) NOT NULL,
412
  product_id bigint(20) NOT NULL,
413
  order_id bigint(20) NOT NULL DEFAULT 0,
414
  order_key varchar(200) NOT NULL,
415
  user_email varchar(200) NOT NULL,
416
  user_id bigint(20) NULL,
417
  downloads_remaining varchar(9) NULL,
418
  access_granted datetime NOT NULL default '0000-00-00 00:00:00',
419
  access_expires datetime NULL default null,
420
  download_count bigint(20) NOT NULL DEFAULT 0,
421
  PRIMARY KEY  (permission_id),
422
  KEY download_order_key_product (product_id,order_id,order_key($max_index_length),download_id),
423
  KEY download_order_product (download_id,order_id,product_id)
424
) $collate;
425
CREATE TABLE {$wpdb->prefix}woocommerce_order_items (
426
  order_item_id bigint(20) NOT NULL auto_increment,
427
  order_item_name longtext NOT NULL,
428
  order_item_type varchar(200) NOT NULL DEFAULT '',
429
  order_id bigint(20) NOT NULL,
430
  PRIMARY KEY  (order_item_id),
431
  KEY order_id (order_id)
432
) $collate;
433
CREATE TABLE {$wpdb->prefix}woocommerce_order_itemmeta (
434
  meta_id bigint(20) NOT NULL auto_increment,
435
  order_item_id bigint(20) NOT NULL,
436
  meta_key varchar(255) default NULL,
437
  meta_value longtext NULL,
438
  PRIMARY KEY  (meta_id),
439
  KEY order_item_id (order_item_id),
440
  KEY meta_key (meta_key($max_index_length))
441
) $collate;
442
CREATE TABLE {$wpdb->prefix}woocommerce_tax_rates (
443
  tax_rate_id bigint(20) NOT NULL auto_increment,
444
  tax_rate_country varchar(200) NOT NULL DEFAULT '',
445
  tax_rate_state varchar(200) NOT NULL DEFAULT '',
446
  tax_rate varchar(200) NOT NULL DEFAULT '',
447
  tax_rate_name varchar(200) NOT NULL DEFAULT '',
448
  tax_rate_priority bigint(20) NOT NULL,
449
  tax_rate_compound int(1) NOT NULL DEFAULT 0,
450
  tax_rate_shipping int(1) NOT NULL DEFAULT 1,
451
  tax_rate_order bigint(20) NOT NULL,
452
  tax_rate_class varchar(200) NOT NULL DEFAULT '',
453
  PRIMARY KEY  (tax_rate_id),
454
  KEY tax_rate_country (tax_rate_country($max_index_length)),
455
  KEY tax_rate_state (tax_rate_state($max_index_length)),
456
  KEY tax_rate_class (tax_rate_class($max_index_length)),
457
  KEY tax_rate_priority (tax_rate_priority)
458
) $collate;
459
CREATE TABLE {$wpdb->prefix}woocommerce_tax_rate_locations (
460
  location_id bigint(20) NOT NULL auto_increment,
461
  location_code varchar(255) NOT NULL,
462
  tax_rate_id bigint(20) NOT NULL,
463
  location_type varchar(40) NOT NULL,
464
  PRIMARY KEY  (location_id),
465
  KEY tax_rate_id (tax_rate_id),
466
  KEY location_type (location_type),
467
  KEY location_type_code (location_type(40),location_code(90))
468
) $collate;
469
CREATE TABLE {$wpdb->prefix}woocommerce_shipping_zones (
470
  zone_id bigint(20) NOT NULL auto_increment,
471
  zone_name varchar(255) NOT NULL,
472
  zone_order bigint(20) NOT NULL,
473
  PRIMARY KEY  (zone_id)
474
) $collate;
475
CREATE TABLE {$wpdb->prefix}woocommerce_shipping_zone_locations (
476
  location_id bigint(20) NOT NULL auto_increment,
477
  zone_id bigint(20) NOT NULL,
478
  location_code varchar(255) NOT NULL,
479
  location_type varchar(40) NOT NULL,
480
  PRIMARY KEY  (location_id),
481
  KEY location_id (location_id),
482
  KEY location_type (location_type),
483
  KEY location_type_code (location_type(40),location_code(90))
484
) $collate;
485
CREATE TABLE {$wpdb->prefix}woocommerce_shipping_zone_methods (
486
  zone_id bigint(20) NOT NULL,
487
  instance_id bigint(20) NOT NULL auto_increment,
488
  method_id varchar(255) NOT NULL,
489
  method_order bigint(20) NOT NULL,
490
  PRIMARY KEY  (instance_id)
491
) $collate;
492
CREATE TABLE {$wpdb->prefix}woocommerce_payment_tokens (
493
  token_id bigint(20) NOT NULL auto_increment,
494
  gateway_id varchar(255) NOT NULL,
495
  token text NOT NULL,
496
  user_id bigint(20) NOT NULL DEFAULT '0',
497
  type varchar(255) NOT NULL,
498
  is_default tinyint(1) NOT NULL DEFAULT '0',
499
  PRIMARY KEY  (token_id),
500
  KEY user_id (user_id)
501
) $collate;
502
CREATE TABLE {$wpdb->prefix}woocommerce_payment_tokenmeta (
503
  meta_id bigint(20) NOT NULL auto_increment,
504
  payment_token_id bigint(20) NOT NULL,
505
  meta_key varchar(255) NULL,
506
  meta_value longtext NULL,
507
  PRIMARY KEY  (meta_id),
508
  KEY payment_token_id (payment_token_id),
509
  KEY meta_key (meta_key)
510
) $collate;
511
		";
512
513
		// Term meta is only needed for old installs.
514
		if ( ! function_exists( 'get_term_meta' ) ) {
515
			$tables .= "
516
CREATE TABLE {$wpdb->prefix}woocommerce_termmeta (
517
  meta_id bigint(20) NOT NULL auto_increment,
518
  woocommerce_term_id bigint(20) NOT NULL,
519
  meta_key varchar(255) default NULL,
520
  meta_value longtext NULL,
521
  PRIMARY KEY  (meta_id),
522
  KEY woocommerce_term_id (woocommerce_term_id),
523
  KEY meta_key (meta_key($max_index_length))
524
) $collate;
525
			";
526
		}
527
528
		return $tables;
529
	}
530
531
	/**
532
	 * Create roles and capabilities.
533
	 */
534
	public static function create_roles() {
535
		global $wp_roles;
536
537
		if ( ! class_exists( 'WP_Roles' ) ) {
538
			return;
539
		}
540
541
		if ( ! isset( $wp_roles ) ) {
542
			$wp_roles = new WP_Roles();
543
		}
544
545
		// Customer role
546
		add_role( 'customer', __( 'Customer', 'woocommerce' ), array(
547
			'read' 					=> true
548
		) );
549
550
		// Shop manager role
551
		add_role( 'shop_manager', __( 'Shop Manager', 'woocommerce' ), array(
552
			'level_9'                => true,
553
			'level_8'                => true,
554
			'level_7'                => true,
555
			'level_6'                => true,
556
			'level_5'                => true,
557
			'level_4'                => true,
558
			'level_3'                => true,
559
			'level_2'                => true,
560
			'level_1'                => true,
561
			'level_0'                => true,
562
			'read'                   => true,
563
			'read_private_pages'     => true,
564
			'read_private_posts'     => true,
565
			'edit_users'             => true,
566
			'edit_posts'             => true,
567
			'edit_pages'             => true,
568
			'edit_published_posts'   => true,
569
			'edit_published_pages'   => true,
570
			'edit_private_pages'     => true,
571
			'edit_private_posts'     => true,
572
			'edit_others_posts'      => true,
573
			'edit_others_pages'      => true,
574
			'publish_posts'          => true,
575
			'publish_pages'          => true,
576
			'delete_posts'           => true,
577
			'delete_pages'           => true,
578
			'delete_private_pages'   => true,
579
			'delete_private_posts'   => true,
580
			'delete_published_pages' => true,
581
			'delete_published_posts' => true,
582
			'delete_others_posts'    => true,
583
			'delete_others_pages'    => true,
584
			'manage_categories'      => true,
585
			'manage_links'           => true,
586
			'moderate_comments'      => true,
587
			'unfiltered_html'        => true,
588
			'upload_files'           => true,
589
			'export'                 => true,
590
			'import'                 => true,
591
			'list_users'             => true
592
		) );
593
594
		$capabilities = self::get_core_capabilities();
595
596
		foreach ( $capabilities as $cap_group ) {
597
			foreach ( $cap_group as $cap ) {
598
				$wp_roles->add_cap( 'shop_manager', $cap );
599
				$wp_roles->add_cap( 'administrator', $cap );
600
			}
601
		}
602
	}
603
604
	/**
605
	 * Get capabilities for WooCommerce - these are assigned to admin/shop manager during installation or reset.
606
	 *
607
	 * @return array
608
	 */
609
	 private static function get_core_capabilities() {
610
		$capabilities = array();
611
612
		$capabilities['core'] = array(
613
			'manage_woocommerce',
614
			'view_woocommerce_reports'
615
		);
616
617
		$capability_types = array( 'product', 'shop_order', 'shop_coupon', 'shop_webhook' );
618
619
		foreach ( $capability_types as $capability_type ) {
620
621
			$capabilities[ $capability_type ] = array(
622
				// Post type
623
				"edit_{$capability_type}",
624
				"read_{$capability_type}",
625
				"delete_{$capability_type}",
626
				"edit_{$capability_type}s",
627
				"edit_others_{$capability_type}s",
628
				"publish_{$capability_type}s",
629
				"read_private_{$capability_type}s",
630
				"delete_{$capability_type}s",
631
				"delete_private_{$capability_type}s",
632
				"delete_published_{$capability_type}s",
633
				"delete_others_{$capability_type}s",
634
				"edit_private_{$capability_type}s",
635
				"edit_published_{$capability_type}s",
636
637
				// Terms
638
				"manage_{$capability_type}_terms",
639
				"edit_{$capability_type}_terms",
640
				"delete_{$capability_type}_terms",
641
				"assign_{$capability_type}_terms"
642
			);
643
		}
644
645
		return $capabilities;
646
	}
647
648
	/**
649
	 * woocommerce_remove_roles function.
650
	 */
651
	public static function remove_roles() {
652
		global $wp_roles;
653
654
		if ( ! class_exists( 'WP_Roles' ) ) {
655
			return;
656
		}
657
658
		if ( ! isset( $wp_roles ) ) {
659
			$wp_roles = new WP_Roles();
660
		}
661
662
		$capabilities = self::get_core_capabilities();
663
664
		foreach ( $capabilities as $cap_group ) {
665
			foreach ( $cap_group as $cap ) {
666
				$wp_roles->remove_cap( 'shop_manager', $cap );
667
				$wp_roles->remove_cap( 'administrator', $cap );
668
			}
669
		}
670
671
		remove_role( 'customer' );
672
		remove_role( 'shop_manager' );
673
	}
674
675
	/**
676
	 * Create files/directories.
677
	 */
678
	private static function create_files() {
679
		// Install files and folders for uploading files and prevent hotlinking
680
		$upload_dir      = wp_upload_dir();
681
		$download_method = get_option( 'woocommerce_file_download_method', 'force' );
682
683
		$files = array(
684
			array(
685
				'base' 		=> $upload_dir['basedir'] . '/woocommerce_uploads',
686
				'file' 		=> 'index.html',
687
				'content' 	=> ''
688
			),
689
			array(
690
				'base' 		=> WC_LOG_DIR,
691
				'file' 		=> '.htaccess',
692
				'content' 	=> 'deny from all'
693
			),
694
			array(
695
				'base' 		=> WC_LOG_DIR,
696
				'file' 		=> 'index.html',
697
				'content' 	=> ''
698
			)
699
		);
700
701
		if ( 'redirect' !== $download_method ) {
702
			$files[] = array(
703
				'base' 		=> $upload_dir['basedir'] . '/woocommerce_uploads',
704
				'file' 		=> '.htaccess',
705
				'content' 	=> 'deny from all'
706
			);
707
		}
708
709
		foreach ( $files as $file ) {
710
			if ( wp_mkdir_p( $file['base'] ) && ! file_exists( trailingslashit( $file['base'] ) . $file['file'] ) ) {
711
				if ( $file_handle = @fopen( trailingslashit( $file['base'] ) . $file['file'], 'w' ) ) {
712
					fwrite( $file_handle, $file['content'] );
713
					fclose( $file_handle );
714
				}
715
			}
716
		}
717
	}
718
719
	/**
720
	 * Show plugin changes. Code adapted from W3 Total Cache.
721
	 */
722
	public static function in_plugin_update_message( $args ) {
723
		$transient_name = 'wc_upgrade_notice_' . $args['Version'];
724
725
		if ( false === ( $upgrade_notice = get_transient( $transient_name ) ) ) {
726
			$response = wp_safe_remote_get( 'https://plugins.svn.wordpress.org/woocommerce/trunk/readme.txt' );
727
728
			if ( ! is_wp_error( $response ) && ! empty( $response['body'] ) ) {
729
				$upgrade_notice = self::parse_update_notice( $response['body'] );
730
				set_transient( $transient_name, $upgrade_notice, DAY_IN_SECONDS );
731
			}
732
		}
733
734
		echo wp_kses_post( $upgrade_notice );
735
	}
736
737
	/**
738
	 * Parse update notice from readme file.
739
	 * @param  string $content
740
	 * @return string
741
	 */
742
	private static function parse_update_notice( $content ) {
743
		// Output Upgrade Notice
744
		$matches        = null;
745
		$regexp         = '~==\s*Upgrade Notice\s*==\s*=\s*(.*)\s*=(.*)(=\s*' . preg_quote( WC_VERSION ) . '\s*=|$)~Uis';
746
		$upgrade_notice = '';
747
748
		if ( preg_match( $regexp, $content, $matches ) ) {
749
			$version = trim( $matches[1] );
750
			$notices = (array) preg_split('~[\r\n]+~', trim( $matches[2] ) );
751
752
			if ( version_compare( WC_VERSION, $version, '<' ) ) {
753
754
				$upgrade_notice .= '<div class="wc_plugin_upgrade_notice">';
755
756
				foreach ( $notices as $index => $line ) {
757
					$upgrade_notice .= wp_kses_post( preg_replace( '~\[([^\]]*)\]\(([^\)]*)\)~', '<a href="${2}">${1}</a>', $line ) );
758
				}
759
760
				$upgrade_notice .= '</div> ';
761
			}
762
		}
763
764
		return wp_kses_post( $upgrade_notice );
765
	}
766
767
	/**
768
	 * Show action links on the plugin screen.
769
	 *
770
	 * @param	mixed $links Plugin Action links
771
	 * @return	array
772
	 */
773
	public static function plugin_action_links( $links ) {
774
		$action_links = array(
775
			'settings' => '<a href="' . admin_url( 'admin.php?page=wc-settings' ) . '" title="' . esc_attr( __( 'View WooCommerce Settings', 'woocommerce' ) ) . '">' . __( 'Settings', 'woocommerce' ) . '</a>',
776
		);
777
778
		return array_merge( $action_links, $links );
779
	}
780
781
	/**
782
	 * Show row meta on the plugin screen.
783
	 *
784
	 * @param	mixed $links Plugin Row Meta
785
	 * @param	mixed $file  Plugin Base file
786
	 * @return	array
787
	 */
788
	public static function plugin_row_meta( $links, $file ) {
789
		if ( $file == WC_PLUGIN_BASENAME ) {
790
			$row_meta = array(
791
				'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>',
792
				'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>',
793
				'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>',
794
			);
795
796
			return array_merge( $links, $row_meta );
797
		}
798
799
		return (array) $links;
800
	}
801
802
	/**
803
	 * Uninstall tables when MU blog is deleted.
804
	 * @param  array $tables
805
	 * @return string[]
806
	 */
807
	public static function wpmu_drop_tables( $tables ) {
808
		global $wpdb;
809
810
		$tables[] = $wpdb->prefix . 'woocommerce_sessions';
811
		$tables[] = $wpdb->prefix . 'woocommerce_api_keys';
812
		$tables[] = $wpdb->prefix . 'woocommerce_attribute_taxonomies';
813
		$tables[] = $wpdb->prefix . 'woocommerce_downloadable_product_permissions';
814
		$tables[] = $wpdb->prefix . 'woocommerce_termmeta';
815
		$tables[] = $wpdb->prefix . 'woocommerce_tax_rates';
816
		$tables[] = $wpdb->prefix . 'woocommerce_tax_rate_locations';
817
		$tables[] = $wpdb->prefix . 'woocommerce_order_items';
818
		$tables[] = $wpdb->prefix . 'woocommerce_order_itemmeta';
819
820
		return $tables;
821
	}
822
}
823
824
WC_Install::init();
825