WC_Install

WC_Install Class.

Defined (1)

The class is defined in the following location(s).

/includes/class-wc-install.php  
  1. class WC_Install { 
  2.  
  3. /** @var array DB updates and callbacks that need to be run per version */ 
  4. private static $db_updates = array( 
  5. '2.0.0' => array( 
  6. 'wc_update_200_file_paths',  
  7. 'wc_update_200_permalinks',  
  8. 'wc_update_200_subcat_display',  
  9. 'wc_update_200_taxrates',  
  10. 'wc_update_200_line_items',  
  11. 'wc_update_200_images',  
  12. 'wc_update_200_db_version',  
  13. ),  
  14. '2.0.9' => array( 
  15. 'wc_update_209_brazillian_state',  
  16. 'wc_update_209_db_version',  
  17. ),  
  18. '2.1.0' => array( 
  19. 'wc_update_210_remove_pages',  
  20. 'wc_update_210_file_paths',  
  21. 'wc_update_210_db_version',  
  22. ),  
  23. '2.2.0' => array( 
  24. 'wc_update_220_shipping',  
  25. 'wc_update_220_order_status',  
  26. 'wc_update_220_variations',  
  27. 'wc_update_220_attributes',  
  28. 'wc_update_220_db_version',  
  29. ),  
  30. '2.3.0' => array( 
  31. 'wc_update_230_options',  
  32. 'wc_update_230_db_version',  
  33. ),  
  34. '2.4.0' => array( 
  35. 'wc_update_240_options',  
  36. 'wc_update_240_shipping_methods',  
  37. 'wc_update_240_api_keys',  
  38. 'wc_update_240_webhooks',  
  39. 'wc_update_240_refunds',  
  40. 'wc_update_240_db_version',  
  41. ),  
  42. '2.4.1' => array( 
  43. 'wc_update_241_variations',  
  44. 'wc_update_241_db_version',  
  45. ),  
  46. '2.5.0' => array( 
  47. 'wc_update_250_currency',  
  48. 'wc_update_250_db_version',  
  49. ),  
  50. '2.6.0' => array( 
  51. 'wc_update_260_options',  
  52. 'wc_update_260_termmeta',  
  53. 'wc_update_260_zones',  
  54. 'wc_update_260_zone_methods',  
  55. 'wc_update_260_refunds',  
  56. 'wc_update_260_db_version',  
  57. ),  
  58. '3.0.0' => array( 
  59. 'wc_update_300_webhooks',  
  60. 'wc_update_300_grouped_products',  
  61. 'wc_update_300_settings',  
  62. 'wc_update_300_product_visibility',  
  63. 'wc_update_300_db_version',  
  64. ),  
  65. ); 
  66.  
  67. /** @var object Background update class */ 
  68. private static $background_updater; 
  69.  
  70. /** 
  71. * Hook in tabs. 
  72. */ 
  73. public static function init() { 
  74. add_action( 'init', array( __CLASS__, 'check_version' ), 5 ); 
  75. add_action( 'init', array( __CLASS__, 'init_background_updater' ), 5 ); 
  76. add_action( 'admin_init', array( __CLASS__, 'install_actions' ) ); 
  77. add_action( 'in_plugin_update_message-woocommerce/woocommerce.php', array( __CLASS__, 'in_plugin_update_message' ) ); 
  78. add_filter( 'plugin_action_links_' . WC_PLUGIN_BASENAME, array( __CLASS__, 'plugin_action_links' ) ); 
  79. add_filter( 'plugin_row_meta', array( __CLASS__, 'plugin_row_meta' ), 10, 2 ); 
  80. add_filter( 'wpmu_drop_tables', array( __CLASS__, 'wpmu_drop_tables' ) ); 
  81. add_filter( 'cron_schedules', array( __CLASS__, 'cron_schedules' ) ); 
  82. add_action( 'woocommerce_plugin_background_installer', array( __CLASS__, 'background_installer' ), 10, 2 ); 
  83.  
  84. /** 
  85. * Init background updates 
  86. */ 
  87. public static function init_background_updater() { 
  88. include_once( dirname( __FILE__ ) . '/class-wc-background-updater.php' ); 
  89. self::$background_updater = new WC_Background_Updater(); 
  90.  
  91. /** 
  92. * Check WooCommerce version and run the updater is required. 
  93. * This check is done on all requests and runs if he versions do not match. 
  94. */ 
  95. public static function check_version() { 
  96. if ( ! defined( 'IFRAME_REQUEST' ) && get_option( 'woocommerce_version' ) !== WC()->version ) { 
  97. self::install(); 
  98. do_action( 'woocommerce_updated' ); 
  99.  
  100. /** 
  101. * Install actions when a update button is clicked within the admin area. 
  102. * This function is hooked into admin_init to affect admin only. 
  103. */ 
  104. public static function install_actions() { 
  105. if ( ! empty( $_GET['do_update_woocommerce'] ) ) { 
  106. self::update(); 
  107. WC_Admin_Notices::add_notice( 'update' ); 
  108. if ( ! empty( $_GET['force_update_woocommerce'] ) ) { 
  109. do_action( 'wp_wc_updater_cron' ); 
  110. wp_safe_redirect( admin_url( 'admin.php?page=wc-settings' ) ); 
  111. exit; 
  112.  
  113. /** 
  114. * Install WC. 
  115. */ 
  116. public static function install() { 
  117. global $wpdb; 
  118.  
  119. if ( ! is_blog_installed() ) { 
  120. return; 
  121.  
  122. if ( ! defined( 'WC_INSTALLING' ) ) { 
  123. define( 'WC_INSTALLING', true ); 
  124.  
  125. // Ensure needed classes are loaded 
  126. include_once( dirname( __FILE__ ) . '/admin/class-wc-admin-notices.php' ); 
  127.  
  128. self::create_options(); 
  129. self::create_tables(); 
  130. self::create_roles(); 
  131.  
  132. // Register post types 
  133. WC_Post_types::register_post_types(); 
  134. WC_Post_types::register_taxonomies(); 
  135.  
  136. // Also register endpoints - this needs to be done prior to rewrite rule flush 
  137. WC()->query->init_query_vars(); 
  138. WC()->query->add_endpoints(); 
  139. WC_API::add_endpoint(); 
  140. WC_Auth::add_endpoint(); 
  141.  
  142. self::create_terms(); 
  143. self::create_cron_jobs(); 
  144. self::create_files(); 
  145.  
  146. // Queue upgrades/setup wizard 
  147. $current_wc_version = get_option( 'woocommerce_version', null ); 
  148. $current_db_version = get_option( 'woocommerce_db_version', null ); 
  149.  
  150. WC_Admin_Notices::remove_all_notices(); 
  151.  
  152. // No versions? This is a new install :) 
  153. if ( is_null( $current_wc_version ) && is_null( $current_db_version ) && apply_filters( 'woocommerce_enable_setup_wizard', true ) ) { 
  154. WC_Admin_Notices::add_notice( 'install' ); 
  155. set_transient( '_wc_activation_redirect', 1, 30 ); 
  156.  
  157. // No page? Let user run wizard again.. 
  158. } elseif ( ! get_option( 'woocommerce_cart_page_id' ) ) { 
  159. WC_Admin_Notices::add_notice( 'install' ); 
  160.  
  161. if ( ! is_null( $current_db_version ) && version_compare( $current_db_version, max( array_keys( self::$db_updates ) ), '<' ) ) { 
  162. WC_Admin_Notices::add_notice( 'update' ); 
  163. } else { 
  164. self::update_db_version(); 
  165.  
  166. self::update_wc_version(); 
  167.  
  168. // Flush rules after install 
  169. do_action( 'woocommerce_flush_rewrite_rules' ); 
  170. delete_transient( 'wc_attribute_taxonomies' ); 
  171.  
  172. /** 
  173. * Deletes all expired transients. The multi-table delete syntax is used 
  174. * to delete the transient record from table a, and the corresponding 
  175. * transient_timeout record from table b. 
  176. * Based on code inside core's upgrade_network() function. 
  177. */ 
  178. $sql = "DELETE a, b FROM $wpdb->options a, $wpdb->options b 
  179. WHERE a.option_name LIKE %s 
  180. AND a.option_name NOT LIKE %s 
  181. AND b.option_name = CONCAT( '_transient_timeout_', SUBSTRING( a.option_name, 12 ) ) 
  182. AND b.option_value < %d"; 
  183. $wpdb->query( $wpdb->prepare( $sql, $wpdb->esc_like( '_transient_' ) . '%', $wpdb->esc_like( '_transient_timeout_' ) . '%', time() ) ); 
  184.  
  185. // Trigger action 
  186. do_action( 'woocommerce_installed' ); 
  187.  
  188. /** 
  189. * Update WC version to current. 
  190. */ 
  191. private static function update_wc_version() { 
  192. delete_option( 'woocommerce_version' ); 
  193. add_option( 'woocommerce_version', WC()->version ); 
  194.  
  195. /** 
  196. * Get list of DB update callbacks. 
  197. * @since 3.0.0 
  198. * @return array 
  199. */ 
  200. public static function get_db_update_callbacks() { 
  201. return self::$db_updates; 
  202.  
  203. /** 
  204. * Push all needed DB updates to the queue for processing. 
  205. */ 
  206. private static function update() { 
  207. $current_db_version = get_option( 'woocommerce_db_version' ); 
  208. $logger = wc_get_logger(); 
  209. $update_queued = false; 
  210.  
  211. foreach ( self::get_db_update_callbacks() as $version => $update_callbacks ) { 
  212. if ( version_compare( $current_db_version, $version, '<' ) ) { 
  213. foreach ( $update_callbacks as $update_callback ) { 
  214. $logger->info( 
  215. sprintf( 'Queuing %s - %s', $version, $update_callback ),  
  216. array( 'source' => 'wc_db_updates' ) 
  217. ); 
  218. self::$background_updater->push_to_queue( $update_callback ); 
  219. $update_queued = true; 
  220.  
  221. if ( $update_queued ) { 
  222. self::$background_updater->save()->dispatch(); 
  223.  
  224. /** 
  225. * Update DB version to current. 
  226. * @param string $version 
  227. */ 
  228. public static function update_db_version( $version = null ) { 
  229. delete_option( 'woocommerce_db_version' ); 
  230. add_option( 'woocommerce_db_version', is_null( $version ) ? WC()->version : $version ); 
  231.  
  232. /** 
  233. * Add more cron schedules. 
  234. * @param array $schedules 
  235. * @return array 
  236. */ 
  237. public static function cron_schedules( $schedules ) { 
  238. $schedules['monthly'] = array( 
  239. 'interval' => 2635200,  
  240. 'display' => __( 'Monthly', 'woocommerce' ),  
  241. ); 
  242. return $schedules; 
  243.  
  244. /** 
  245. * Create cron jobs (clear them first). 
  246. */ 
  247. private static function create_cron_jobs() { 
  248. wp_clear_scheduled_hook( 'woocommerce_scheduled_sales' ); 
  249. wp_clear_scheduled_hook( 'woocommerce_cancel_unpaid_orders' ); 
  250. wp_clear_scheduled_hook( 'woocommerce_cleanup_sessions' ); 
  251. wp_clear_scheduled_hook( 'woocommerce_geoip_updater' ); 
  252. wp_clear_scheduled_hook( 'woocommerce_tracker_send_event' ); 
  253.  
  254. $ve = get_option( 'gmt_offset' ) > 0 ? '-' : '+'; 
  255.  
  256. wp_schedule_event( strtotime( '00:00 tomorrow ' . $ve . get_option( 'gmt_offset' ) . ' HOURS' ), 'daily', 'woocommerce_scheduled_sales' ); 
  257.  
  258. $held_duration = get_option( 'woocommerce_hold_stock_minutes', '60' ); 
  259.  
  260. if ( '' != $held_duration ) { 
  261. wp_schedule_single_event( time() + ( absint( $held_duration ) * 60 ), 'woocommerce_cancel_unpaid_orders' ); 
  262.  
  263. wp_schedule_event( time(), 'twicedaily', 'woocommerce_cleanup_sessions' ); 
  264. wp_schedule_event( strtotime( 'first tuesday of next month' ), 'monthly', 'woocommerce_geoip_updater' ); 
  265. wp_schedule_event( time(), apply_filters( 'woocommerce_tracker_event_recurrence', 'daily' ), 'woocommerce_tracker_send_event' ); 
  266.  
  267. /** 
  268. * Create pages that the plugin relies on, storing page IDs in variables. 
  269. */ 
  270. public static function create_pages() { 
  271. include_once( dirname( __FILE__ ) . '/admin/wc-admin-functions.php' ); 
  272.  
  273. $pages = apply_filters( 'woocommerce_create_pages', array( 
  274. 'shop' => array( 
  275. 'name' => _x( 'shop', 'Page slug', 'woocommerce' ),  
  276. 'title' => _x( 'Shop', 'Page title', 'woocommerce' ),  
  277. 'content' => '',  
  278. ),  
  279. 'cart' => array( 
  280. 'name' => _x( 'cart', 'Page slug', 'woocommerce' ),  
  281. 'title' => _x( 'Cart', 'Page title', 'woocommerce' ),  
  282. 'content' => '[' . apply_filters( 'woocommerce_cart_shortcode_tag', 'woocommerce_cart' ) . ']',  
  283. ),  
  284. 'checkout' => array( 
  285. 'name' => _x( 'checkout', 'Page slug', 'woocommerce' ),  
  286. 'title' => _x( 'Checkout', 'Page title', 'woocommerce' ),  
  287. 'content' => '[' . apply_filters( 'woocommerce_checkout_shortcode_tag', 'woocommerce_checkout' ) . ']',  
  288. ),  
  289. 'myaccount' => array( 
  290. 'name' => _x( 'my-account', 'Page slug', 'woocommerce' ),  
  291. 'title' => _x( 'My account', 'Page title', 'woocommerce' ),  
  292. 'content' => '[' . apply_filters( 'woocommerce_my_account_shortcode_tag', 'woocommerce_my_account' ) . ']',  
  293. ),  
  294. ) ); 
  295.  
  296. foreach ( $pages as $key => $page ) { 
  297. wc_create_page( esc_sql( $page['name'] ), 'woocommerce_' . $key . '_page_id', $page['title'], $page['content'], ! empty( $page['parent'] ) ? wc_get_page_id( $page['parent'] ) : '' ); 
  298.  
  299. delete_transient( 'woocommerce_cache_excluded_uris' ); 
  300.  
  301. /** 
  302. * Default options. 
  303. * Sets up the default options used on the settings page. 
  304. */ 
  305. private static function create_options() { 
  306. // Include settings so that we can run through defaults 
  307. include_once( dirname( __FILE__ ) . '/admin/class-wc-admin-settings.php' ); 
  308.  
  309. $settings = WC_Admin_Settings::get_settings_pages(); 
  310.  
  311. foreach ( $settings as $section ) { 
  312. if ( ! method_exists( $section, 'get_settings' ) ) { 
  313. continue; 
  314. $subsections = array_unique( array_merge( array( '' ), array_keys( $section->get_sections() ) ) ); 
  315.  
  316. foreach ( $subsections as $subsection ) { 
  317. foreach ( $section->get_settings( $subsection ) as $value ) { 
  318. if ( isset( $value['default'] ) && isset( $value['id'] ) ) { 
  319. $autoload = isset( $value['autoload'] ) ? (bool) $value['autoload'] : true; 
  320. add_option( $value['id'], $value['default'], '', ( $autoload ? 'yes' : 'no' ) ); 
  321.  
  322. /** 
  323. * Add the default terms for WC taxonomies - product types and order statuses. Modify this at your own risk. 
  324. */ 
  325. public static function create_terms() { 
  326. $taxonomies = array( 
  327. 'product_type' => array( 
  328. 'simple',  
  329. 'grouped',  
  330. 'variable',  
  331. 'external',  
  332. ),  
  333. 'product_visibility' => array( 
  334. 'exclude-from-search',  
  335. 'exclude-from-catalog',  
  336. 'featured',  
  337. 'outofstock',  
  338. 'rated-1',  
  339. 'rated-2',  
  340. 'rated-3',  
  341. 'rated-4',  
  342. 'rated-5',  
  343. ),  
  344. ); 
  345.  
  346. foreach ( $taxonomies as $taxonomy => $terms ) { 
  347. foreach ( $terms as $term ) { 
  348. if ( ! get_term_by( 'name', $term, $taxonomy ) ) { 
  349. wp_insert_term( $term, $taxonomy ); 
  350.  
  351. /** 
  352. * Set up the database tables which the plugin needs to function. 
  353. * Tables: 
  354. * woocommerce_attribute_taxonomies - Table for storing attribute taxonomies - these are user defined 
  355. * woocommerce_termmeta - Term meta table - sadly WordPress does not have termmeta so we need our own 
  356. * woocommerce_downloadable_product_permissions - Table for storing user and guest download permissions. 
  357. * KEY(order_id, product_id, download_id) used for organizing downloads on the My Account page 
  358. * woocommerce_order_items - Order line items are stored in a table to make them easily queryable for reports 
  359. * woocommerce_order_itemmeta - Order line item meta is stored in a table for storing extra data. 
  360. * woocommerce_tax_rates - Tax Rates are stored inside 2 tables making tax queries simple and efficient. 
  361. * woocommerce_tax_rate_locations - Each rate can be applied to more than one postcode/city hence the second table. 
  362. */ 
  363. private static function create_tables() { 
  364. global $wpdb; 
  365.  
  366. $wpdb->hide_errors(); 
  367.  
  368. require_once( ABSPATH . 'wp-admin/includes/upgrade.php' ); 
  369.  
  370. /** 
  371. * Before updating with DBDELTA, remove any primary keys which could be 
  372. * modified due to schema updates. 
  373. */ 
  374. if ( $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->prefix}woocommerce_downloadable_product_permissions';" ) ) { 
  375. if ( ! $wpdb->get_var( "SHOW COLUMNS FROM `{$wpdb->prefix}woocommerce_downloadable_product_permissions` LIKE 'permission_id';" ) ) { 
  376. $wpdb->query( "ALTER TABLE {$wpdb->prefix}woocommerce_downloadable_product_permissions DROP PRIMARY KEY, ADD `permission_id` BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT;" ); 
  377.  
  378. dbDelta( self::get_schema() ); 
  379.  
  380. $index_exists = $wpdb->get_row( "SHOW INDEX FROM {$wpdb->comments} WHERE column_name = 'comment_type' and key_name = 'woo_idx_comment_type'" ); 
  381.  
  382. if ( is_null( $index_exists ) ) { 
  383. // Add an index to the field comment_type to improve the response time of the query 
  384. // used by WC_Comments::wp_count_comments() to get the number of comments by type. 
  385. $wpdb->query( "ALTER TABLE {$wpdb->comments} ADD INDEX woo_idx_comment_type (comment_type)" ); 
  386.  
  387. /** 
  388. * Get Table schema. 
  389. * https://github.com/woocommerce/woocommerce/wiki/Database-Description/ 
  390. * A note on indexes; Indexes have a maximum size of 767 bytes. Historically, we haven't need to be concerned about that. 
  391. * As of WordPress 4.2, however, we moved to utf8mb4, which uses 4 bytes per character. This means that an index which 
  392. * used to have room for floor(767/3) = 255 characters, now only has room for floor(767/4) = 191 characters. 
  393. * Changing indexes may cause duplicate index notices in logs due to https://core.trac.wordpress.org/ticket/34870 but dropping 
  394. * indexes first causes too much load on some servers/larger DB. 
  395. * @return string 
  396. */ 
  397. private static function get_schema() { 
  398. global $wpdb; 
  399.  
  400. $collate = ''; 
  401.  
  402. if ( $wpdb->has_cap( 'collation' ) ) { 
  403. $collate = $wpdb->get_charset_collate(); 
  404.  
  405. $tables = " 
  406. CREATE TABLE {$wpdb->prefix}woocommerce_sessions ( 
  407. session_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,  
  408. session_key char(32) NOT NULL,  
  409. session_value longtext NOT NULL,  
  410. session_expiry BIGINT UNSIGNED NOT NULL,  
  411. PRIMARY KEY (session_key),  
  412. UNIQUE KEY session_id (session_id) 
  413. ) $collate; 
  414. CREATE TABLE {$wpdb->prefix}woocommerce_api_keys ( 
  415. key_id BIGINT UNSIGNED NOT NULL auto_increment,  
  416. user_id BIGINT UNSIGNED NOT NULL,  
  417. description varchar(200) NULL,  
  418. permissions varchar(10) NOT NULL,  
  419. consumer_key char(64) NOT NULL,  
  420. consumer_secret char(43) NOT NULL,  
  421. nonces longtext NULL,  
  422. truncated_key char(7) NOT NULL,  
  423. last_access datetime NULL default null,  
  424. PRIMARY KEY (key_id),  
  425. KEY consumer_key (consumer_key),  
  426. KEY consumer_secret (consumer_secret) 
  427. ) $collate; 
  428. CREATE TABLE {$wpdb->prefix}woocommerce_attribute_taxonomies ( 
  429. attribute_id BIGINT UNSIGNED NOT NULL auto_increment,  
  430. attribute_name varchar(200) NOT NULL,  
  431. attribute_label varchar(200) NULL,  
  432. attribute_type varchar(20) NOT NULL,  
  433. attribute_orderby varchar(20) NOT NULL,  
  434. attribute_public int(1) NOT NULL DEFAULT 1,  
  435. PRIMARY KEY (attribute_id),  
  436. KEY attribute_name (attribute_name(20)) 
  437. ) $collate; 
  438. CREATE TABLE {$wpdb->prefix}woocommerce_downloadable_product_permissions ( 
  439. permission_id BIGINT UNSIGNED NOT NULL auto_increment,  
  440. download_id varchar(32) NOT NULL,  
  441. product_id BIGINT UNSIGNED NOT NULL,  
  442. order_id BIGINT UNSIGNED NOT NULL DEFAULT 0,  
  443. order_key varchar(200) NOT NULL,  
  444. user_email varchar(200) NOT NULL,  
  445. user_id BIGINT UNSIGNED NULL,  
  446. downloads_remaining varchar(9) NULL,  
  447. access_granted datetime NOT NULL default '0000-00-00 00:00:00',  
  448. access_expires datetime NULL default null,  
  449. download_count BIGINT UNSIGNED NOT NULL DEFAULT 0,  
  450. PRIMARY KEY (permission_id),  
  451. KEY download_order_key_product (product_id, order_id, order_key(16), download_id),  
  452. KEY download_order_product (download_id, order_id, product_id) 
  453. ) $collate; 
  454. CREATE TABLE {$wpdb->prefix}woocommerce_order_items ( 
  455. order_item_id BIGINT UNSIGNED NOT NULL auto_increment,  
  456. order_item_name TEXT NOT NULL,  
  457. order_item_type varchar(200) NOT NULL DEFAULT '',  
  458. order_id BIGINT UNSIGNED NOT NULL,  
  459. PRIMARY KEY (order_item_id),  
  460. KEY order_id (order_id) 
  461. ) $collate; 
  462. CREATE TABLE {$wpdb->prefix}woocommerce_order_itemmeta ( 
  463. meta_id BIGINT UNSIGNED NOT NULL auto_increment,  
  464. order_item_id BIGINT UNSIGNED NOT NULL,  
  465. meta_key varchar(255) default NULL,  
  466. meta_value longtext NULL,  
  467. PRIMARY KEY (meta_id),  
  468. KEY order_item_id (order_item_id),  
  469. KEY meta_key (meta_key(32)) 
  470. ) $collate; 
  471. CREATE TABLE {$wpdb->prefix}woocommerce_tax_rates ( 
  472. tax_rate_id BIGINT UNSIGNED NOT NULL auto_increment,  
  473. tax_rate_country varchar(2) NOT NULL DEFAULT '',  
  474. tax_rate_state varchar(200) NOT NULL DEFAULT '',  
  475. tax_rate varchar(8) NOT NULL DEFAULT '',  
  476. tax_rate_name varchar(200) NOT NULL DEFAULT '',  
  477. tax_rate_priority BIGINT UNSIGNED NOT NULL,  
  478. tax_rate_compound int(1) NOT NULL DEFAULT 0,  
  479. tax_rate_shipping int(1) NOT NULL DEFAULT 1,  
  480. tax_rate_order BIGINT UNSIGNED NOT NULL,  
  481. tax_rate_class varchar(200) NOT NULL DEFAULT '',  
  482. PRIMARY KEY (tax_rate_id),  
  483. KEY tax_rate_country (tax_rate_country),  
  484. KEY tax_rate_state (tax_rate_state(2)),  
  485. KEY tax_rate_class (tax_rate_class(10)),  
  486. KEY tax_rate_priority (tax_rate_priority) 
  487. ) $collate; 
  488. CREATE TABLE {$wpdb->prefix}woocommerce_tax_rate_locations ( 
  489. location_id BIGINT UNSIGNED NOT NULL auto_increment,  
  490. location_code varchar(200) NOT NULL,  
  491. tax_rate_id BIGINT UNSIGNED NOT NULL,  
  492. location_type varchar(40) NOT NULL,  
  493. PRIMARY KEY (location_id),  
  494. KEY tax_rate_id (tax_rate_id),  
  495. KEY location_type_code (location_type(10), location_code(20)) 
  496. ) $collate; 
  497. CREATE TABLE {$wpdb->prefix}woocommerce_shipping_zones ( 
  498. zone_id BIGINT UNSIGNED NOT NULL auto_increment,  
  499. zone_name varchar(200) NOT NULL,  
  500. zone_order BIGINT UNSIGNED NOT NULL,  
  501. PRIMARY KEY (zone_id) 
  502. ) $collate; 
  503. CREATE TABLE {$wpdb->prefix}woocommerce_shipping_zone_locations ( 
  504. location_id BIGINT UNSIGNED NOT NULL auto_increment,  
  505. zone_id BIGINT UNSIGNED NOT NULL,  
  506. location_code varchar(200) NOT NULL,  
  507. location_type varchar(40) NOT NULL,  
  508. PRIMARY KEY (location_id),  
  509. KEY location_id (location_id),  
  510. KEY location_type_code (location_type(10), location_code(20)) 
  511. ) $collate; 
  512. CREATE TABLE {$wpdb->prefix}woocommerce_shipping_zone_methods ( 
  513. zone_id BIGINT UNSIGNED NOT NULL,  
  514. instance_id BIGINT UNSIGNED NOT NULL auto_increment,  
  515. method_id varchar(200) NOT NULL,  
  516. method_order BIGINT UNSIGNED NOT NULL,  
  517. is_enabled tinyint(1) NOT NULL DEFAULT '1',  
  518. PRIMARY KEY (instance_id) 
  519. ) $collate; 
  520. CREATE TABLE {$wpdb->prefix}woocommerce_payment_tokens ( 
  521. token_id BIGINT UNSIGNED NOT NULL auto_increment,  
  522. gateway_id varchar(200) NOT NULL,  
  523. token text NOT NULL,  
  524. user_id BIGINT UNSIGNED NOT NULL DEFAULT '0',  
  525. type varchar(200) NOT NULL,  
  526. is_default tinyint(1) NOT NULL DEFAULT '0',  
  527. PRIMARY KEY (token_id),  
  528. KEY user_id (user_id) 
  529. ) $collate; 
  530. CREATE TABLE {$wpdb->prefix}woocommerce_payment_tokenmeta ( 
  531. meta_id BIGINT UNSIGNED NOT NULL auto_increment,  
  532. payment_token_id BIGINT UNSIGNED NOT NULL,  
  533. meta_key varchar(255) NULL,  
  534. meta_value longtext NULL,  
  535. PRIMARY KEY (meta_id),  
  536. KEY payment_token_id (payment_token_id),  
  537. KEY meta_key (meta_key(32)) 
  538. ) $collate; 
  539. CREATE TABLE {$wpdb->prefix}woocommerce_log ( 
  540. log_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,  
  541. timestamp datetime NOT NULL,  
  542. level smallint(4) NOT NULL,  
  543. source varchar(200) NOT NULL,  
  544. message longtext NOT NULL,  
  545. context longtext NULL,  
  546. PRIMARY KEY (log_id),  
  547. KEY level (level) 
  548. ) $collate; 
  549. "; 
  550.  
  551. /** 
  552. * Term meta is only needed for old installs and is now @deprecated by WordPress term meta. 
  553. */ 
  554. if ( ! function_exists( 'get_term_meta' ) ) { 
  555. $tables .= " 
  556. CREATE TABLE {$wpdb->prefix}woocommerce_termmeta ( 
  557. meta_id BIGINT UNSIGNED NOT NULL auto_increment,  
  558. woocommerce_term_id BIGINT UNSIGNED NOT NULL,  
  559. meta_key varchar(255) default NULL,  
  560. meta_value longtext NULL,  
  561. PRIMARY KEY (meta_id),  
  562. KEY woocommerce_term_id (woocommerce_term_id),  
  563. KEY meta_key (meta_key(32)) 
  564. ) $collate; 
  565. "; 
  566.  
  567. return $tables; 
  568.  
  569. /** 
  570. * Create roles and capabilities. 
  571. */ 
  572. public static function create_roles() { 
  573. global $wp_roles; 
  574.  
  575. if ( ! class_exists( 'WP_Roles' ) ) { 
  576. return; 
  577.  
  578. if ( ! isset( $wp_roles ) ) { 
  579. $wp_roles = new WP_Roles(); 
  580.  
  581. // Customer role 
  582. add_role( 'customer', __( 'Customer', 'woocommerce' ), array( 
  583. 'read' => true,  
  584. ) ); 
  585.  
  586. // Shop manager role 
  587. add_role( 'shop_manager', __( 'Shop manager', 'woocommerce' ), array( 
  588. 'level_9' => true,  
  589. 'level_8' => true,  
  590. 'level_7' => true,  
  591. 'level_6' => true,  
  592. 'level_5' => true,  
  593. 'level_4' => true,  
  594. 'level_3' => true,  
  595. 'level_2' => true,  
  596. 'level_1' => true,  
  597. 'level_0' => true,  
  598. 'read' => true,  
  599. 'read_private_pages' => true,  
  600. 'read_private_posts' => true,  
  601. 'edit_users' => true,  
  602. 'edit_posts' => true,  
  603. 'edit_pages' => true,  
  604. 'edit_published_posts' => true,  
  605. 'edit_published_pages' => true,  
  606. 'edit_private_pages' => true,  
  607. 'edit_private_posts' => true,  
  608. 'edit_others_posts' => true,  
  609. 'edit_others_pages' => true,  
  610. 'publish_posts' => true,  
  611. 'publish_pages' => true,  
  612. 'delete_posts' => true,  
  613. 'delete_pages' => true,  
  614. 'delete_private_pages' => true,  
  615. 'delete_private_posts' => true,  
  616. 'delete_published_pages' => true,  
  617. 'delete_published_posts' => true,  
  618. 'delete_others_posts' => true,  
  619. 'delete_others_pages' => true,  
  620. 'manage_categories' => true,  
  621. 'manage_links' => true,  
  622. 'moderate_comments' => true,  
  623. 'unfiltered_html' => true,  
  624. 'upload_files' => true,  
  625. 'export' => true,  
  626. 'import' => true,  
  627. 'list_users' => true,  
  628. ) ); 
  629.  
  630. $capabilities = self::get_core_capabilities(); 
  631.  
  632. foreach ( $capabilities as $cap_group ) { 
  633. foreach ( $cap_group as $cap ) { 
  634. $wp_roles->add_cap( 'shop_manager', $cap ); 
  635. $wp_roles->add_cap( 'administrator', $cap ); 
  636.  
  637. /** 
  638. * Get capabilities for WooCommerce - these are assigned to admin/shop manager during installation or reset. 
  639. * @return array 
  640. */ 
  641. private static function get_core_capabilities() { 
  642. $capabilities = array(); 
  643.  
  644. $capabilities['core'] = array( 
  645. 'manage_woocommerce',  
  646. 'view_woocommerce_reports',  
  647. ); 
  648.  
  649. $capability_types = array( 'product', 'shop_order', 'shop_coupon', 'shop_webhook' ); 
  650.  
  651. foreach ( $capability_types as $capability_type ) { 
  652.  
  653. $capabilities[ $capability_type ] = array( 
  654. // Post type 
  655. "edit_{$capability_type}",  
  656. "read_{$capability_type}",  
  657. "delete_{$capability_type}",  
  658. "edit_{$capability_type}s",  
  659. "edit_others_{$capability_type}s",  
  660. "publish_{$capability_type}s",  
  661. "read_private_{$capability_type}s",  
  662. "delete_{$capability_type}s",  
  663. "delete_private_{$capability_type}s",  
  664. "delete_published_{$capability_type}s",  
  665. "delete_others_{$capability_type}s",  
  666. "edit_private_{$capability_type}s",  
  667. "edit_published_{$capability_type}s",  
  668.  
  669. // Terms 
  670. "manage_{$capability_type}_terms",  
  671. "edit_{$capability_type}_terms",  
  672. "delete_{$capability_type}_terms",  
  673. "assign_{$capability_type}_terms",  
  674. ); 
  675.  
  676. return $capabilities; 
  677.  
  678. /** 
  679. * woocommerce_remove_roles function. 
  680. */ 
  681. public static function remove_roles() { 
  682. global $wp_roles; 
  683.  
  684. if ( ! class_exists( 'WP_Roles' ) ) { 
  685. return; 
  686.  
  687. if ( ! isset( $wp_roles ) ) { 
  688. $wp_roles = new WP_Roles(); 
  689.  
  690. $capabilities = self::get_core_capabilities(); 
  691.  
  692. foreach ( $capabilities as $cap_group ) { 
  693. foreach ( $cap_group as $cap ) { 
  694. $wp_roles->remove_cap( 'shop_manager', $cap ); 
  695. $wp_roles->remove_cap( 'administrator', $cap ); 
  696.  
  697. remove_role( 'customer' ); 
  698. remove_role( 'shop_manager' ); 
  699.  
  700. /** 
  701. * Create files/directories. 
  702. */ 
  703. private static function create_files() { 
  704. // Install files and folders for uploading files and prevent hotlinking 
  705. $upload_dir = wp_upload_dir(); 
  706. $download_method = get_option( 'woocommerce_file_download_method', 'force' ); 
  707.  
  708. $files = array( 
  709. array( 
  710. 'base' => $upload_dir['basedir'] . '/woocommerce_uploads',  
  711. 'file' => 'index.html',  
  712. 'content' => '',  
  713. ),  
  714. array( 
  715. 'base' => WC_LOG_DIR,  
  716. 'file' => '.htaccess',  
  717. 'content' => 'deny from all',  
  718. ),  
  719. array( 
  720. 'base' => WC_LOG_DIR,  
  721. 'file' => 'index.html',  
  722. 'content' => '',  
  723. ),  
  724. ); 
  725.  
  726. if ( 'redirect' !== $download_method ) { 
  727. $files[] = array( 
  728. 'base' => $upload_dir['basedir'] . '/woocommerce_uploads',  
  729. 'file' => '.htaccess',  
  730. 'content' => 'deny from all',  
  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. * Show plugin changes. Code adapted from W3 Total Cache. 
  741. */ 
  742. public static function in_plugin_update_message( $args ) { 
  743. $transient_name = 'wc_upgrade_notice_' . $args['Version']; 
  744.  
  745. if ( false === ( $upgrade_notice = get_transient( $transient_name ) ) ) { 
  746. $response = wp_safe_remote_get( 'https://plugins.svn.wordpress.org/woocommerce/trunk/readme.txt' ); 
  747.  
  748. if ( ! is_wp_error( $response ) && ! empty( $response['body'] ) ) { 
  749. $upgrade_notice = self::parse_update_notice( $response['body'], $args['new_version'] ); 
  750. set_transient( $transient_name, $upgrade_notice, DAY_IN_SECONDS ); 
  751.  
  752. echo wp_kses_post( $upgrade_notice ); 
  753.  
  754. /** 
  755. * Parse update notice from readme file. 
  756. * @param string $content 
  757. * @param string $new_version 
  758. * @return string 
  759. */ 
  760. private static function parse_update_notice( $content, $new_version ) { 
  761. // Output Upgrade Notice. 
  762. $matches = null; 
  763. $regexp = '~==\s*Upgrade Notice\s*==\s*=\s*(.*)\s*=(.*)(=\s*' . preg_quote( WC_VERSION ) . '\s*=|$)~Uis'; 
  764. $upgrade_notice = ''; 
  765.  
  766. if ( preg_match( $regexp, $content, $matches ) ) { 
  767. $notices = (array) preg_split( '~[\r\n]+~', trim( $matches[2] ) ); 
  768.  
  769. // Convert the full version strings to minor versions. 
  770. $notice_version_parts = explode( '.', trim( $matches[1] ) ); 
  771. $current_version_parts = explode( '.', WC_VERSION ); 
  772.  
  773. if ( 3 !== sizeof( $notice_version_parts ) ) { 
  774. return; 
  775.  
  776. $notice_version = $notice_version_parts[0] . '.' . $notice_version_parts[1]; 
  777. $current_version = $current_version_parts[0] . '.' . $current_version_parts[1]; 
  778.  
  779. // Check the latest stable version and ignore trunk. 
  780. if ( version_compare( $current_version, $notice_version, '<' ) ) { 
  781.  
  782. $upgrade_notice .= '</p><p class="wc_plugin_upgrade_notice">'; 
  783.  
  784. foreach ( $notices as $index => $line ) { 
  785. $upgrade_notice .= preg_replace( '~\[([^\]]*)\]\(([^\)]*)\)~', '<a href="${2}">${1}</a>', $line ); 
  786.  
  787. return wp_kses_post( $upgrade_notice ); 
  788.  
  789. /** 
  790. * Show action links on the plugin screen. 
  791. * @param mixed $links Plugin Action links 
  792. * @return array 
  793. */ 
  794. public static function plugin_action_links( $links ) { 
  795. $action_links = array( 
  796. 'settings' => '<a href="' . admin_url( 'admin.php?page=wc-settings' ) . '" aria-label="' . esc_attr__( 'View WooCommerce settings', 'woocommerce' ) . '">' . esc_html__( 'Settings', 'woocommerce' ) . '</a>',  
  797. ); 
  798.  
  799. return array_merge( $action_links, $links ); 
  800.  
  801. /** 
  802. * Show row meta on the plugin screen. 
  803. * @param mixed $links Plugin Row Meta 
  804. * @param mixed $file Plugin Base file 
  805. * @return array 
  806. */ 
  807. public static function plugin_row_meta( $links, $file ) { 
  808. if ( WC_PLUGIN_BASENAME == $file ) { 
  809. $row_meta = array( 
  810. 'docs' => '<a href="' . esc_url( apply_filters( 'woocommerce_docs_url', 'https://docs.woocommerce.com/documentation/plugins/woocommerce/' ) ) . '" aria-label="' . esc_attr__( 'View WooCommerce documentation', 'woocommerce' ) . '">' . esc_html__( 'Docs', 'woocommerce' ) . '</a>',  
  811. 'apidocs' => '<a href="' . esc_url( apply_filters( 'woocommerce_apidocs_url', 'https://docs.woocommerce.com/wc-apidocs/' ) ) . '" aria-label="' . esc_attr__( 'View WooCommerce API docs', 'woocommerce' ) . '">' . esc_html__( 'API docs', 'woocommerce' ) . '</a>',  
  812. 'support' => '<a href="' . esc_url( apply_filters( 'woocommerce_support_url', 'https://woocommerce.com/my-account/tickets/' ) ) . '" aria-label="' . esc_attr__( 'Visit premium customer support', 'woocommerce' ) . '">' . esc_html__( 'Premium support', 'woocommerce' ) . '</a>',  
  813. ); 
  814.  
  815. return array_merge( $links, $row_meta ); 
  816.  
  817. return (array) $links; 
  818.  
  819. /** 
  820. * Uninstall tables when MU blog is deleted. 
  821. * @param array $tables 
  822. * @return string[] 
  823. */ 
  824. public static function wpmu_drop_tables( $tables ) { 
  825. global $wpdb; 
  826.  
  827. $tables[] = $wpdb->prefix . 'woocommerce_sessions'; 
  828. $tables[] = $wpdb->prefix . 'woocommerce_api_keys'; 
  829. $tables[] = $wpdb->prefix . 'woocommerce_attribute_taxonomies'; 
  830. $tables[] = $wpdb->prefix . 'woocommerce_downloadable_product_permissions'; 
  831. $tables[] = $wpdb->prefix . 'woocommerce_termmeta'; 
  832. $tables[] = $wpdb->prefix . 'woocommerce_tax_rates'; 
  833. $tables[] = $wpdb->prefix . 'woocommerce_tax_rate_locations'; 
  834. $tables[] = $wpdb->prefix . 'woocommerce_order_items'; 
  835. $tables[] = $wpdb->prefix . 'woocommerce_order_itemmeta'; 
  836. $tables[] = $wpdb->prefix . 'woocommerce_payment_tokens'; 
  837. $tables[] = $wpdb->prefix . 'woocommerce_shipping_zones'; 
  838. $tables[] = $wpdb->prefix . 'woocommerce_shipping_zone_locations'; 
  839. $tables[] = $wpdb->prefix . 'woocommerce_shipping_zone_methods'; 
  840.  
  841. return $tables; 
  842.  
  843. /** 
  844. * Get slug from path 
  845. * @param string $key 
  846. * @return string 
  847. */ 
  848. private static function format_plugin_slug( $key ) { 
  849. $slug = explode( '/', $key ); 
  850. $slug = explode( '.', end( $slug ) ); 
  851. return $slug[0]; 
  852.  
  853. /** 
  854. * Install a plugin from .org in the background via a cron job (used by 
  855. * installer - opt in). 
  856. * @param string $plugin_to_install_id 
  857. * @param array $plugin_to_install 
  858. * @since 2.6.0 
  859. */ 
  860. public static function background_installer( $plugin_to_install_id, $plugin_to_install ) { 
  861. // Explicitly clear the event. 
  862. wp_clear_scheduled_hook( 'woocommerce_plugin_background_installer', func_get_args() ); 
  863.  
  864. if ( ! empty( $plugin_to_install['repo-slug'] ) ) { 
  865. require_once( ABSPATH . 'wp-admin/includes/file.php' ); 
  866. require_once( ABSPATH . 'wp-admin/includes/plugin-install.php' ); 
  867. require_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' ); 
  868. require_once( ABSPATH . 'wp-admin/includes/plugin.php' ); 
  869.  
  870. WP_Filesystem(); 
  871.  
  872. $skin = new Automatic_Upgrader_Skin; 
  873. $upgrader = new WP_Upgrader( $skin ); 
  874. $installed_plugins = array_map( array( __CLASS__, 'format_plugin_slug' ), array_keys( get_plugins() ) ); 
  875. $plugin_slug = $plugin_to_install['repo-slug']; 
  876. $plugin = $plugin_slug . '/' . $plugin_slug . '.php'; 
  877. $installed = false; 
  878. $activate = false; 
  879.  
  880. // See if the plugin is installed already 
  881. if ( in_array( $plugin_to_install['repo-slug'], $installed_plugins ) ) { 
  882. $installed = true; 
  883. $activate = ! is_plugin_active( $plugin ); 
  884.  
  885. // Install this thing! 
  886. if ( ! $installed ) { 
  887. // Suppress feedback 
  888. ob_start(); 
  889.  
  890. try { 
  891. $plugin_information = plugins_api( 'plugin_information', array( 
  892. 'slug' => $plugin_to_install['repo-slug'],  
  893. 'fields' => array( 
  894. 'short_description' => false,  
  895. 'sections' => false,  
  896. 'requires' => false,  
  897. 'rating' => false,  
  898. 'ratings' => false,  
  899. 'downloaded' => false,  
  900. 'last_updated' => false,  
  901. 'added' => false,  
  902. 'tags' => false,  
  903. 'homepage' => false,  
  904. 'donate_link' => false,  
  905. 'author_profile' => false,  
  906. 'author' => false,  
  907. ),  
  908. ) ); 
  909.  
  910. if ( is_wp_error( $plugin_information ) ) { 
  911. throw new Exception( $plugin_information->get_error_message() ); 
  912.  
  913. $package = $plugin_information->download_link; 
  914. $download = $upgrader->download_package( $package ); 
  915.  
  916. if ( is_wp_error( $download ) ) { 
  917. throw new Exception( $download->get_error_message() ); 
  918.  
  919. $working_dir = $upgrader->unpack_package( $download, true ); 
  920.  
  921. if ( is_wp_error( $working_dir ) ) { 
  922. throw new Exception( $working_dir->get_error_message() ); 
  923.  
  924. $result = $upgrader->install_package( array( 
  925. 'source' => $working_dir,  
  926. 'destination' => WP_PLUGIN_DIR,  
  927. 'clear_destination' => false,  
  928. 'abort_if_destination_exists' => false,  
  929. 'clear_working' => true,  
  930. 'hook_extra' => array( 
  931. 'type' => 'plugin',  
  932. 'action' => 'install',  
  933. ),  
  934. ) ); 
  935.  
  936. if ( is_wp_error( $result ) ) { 
  937. throw new Exception( $result->get_error_message() ); 
  938.  
  939. $activate = true; 
  940.  
  941. } catch ( Exception $e ) { 
  942. WC_Admin_Notices::add_custom_notice( 
  943. $plugin_to_install_id . '_install_error',  
  944. sprintf( 
  945. __( '%1$s could not be installed (%2$s). <a href="%3$s">Please install it manually by clicking here.</a>', 'woocommerce' ),  
  946. $plugin_to_install['name'],  
  947. $e->getMessage(),  
  948. esc_url( admin_url( 'index.php?wc-install-plugin-redirect=' . $plugin_to_install['repo-slug'] ) ) 
  949. ); 
  950.  
  951. // Discard feedback 
  952. ob_end_clean(); 
  953.  
  954. wp_clean_plugins_cache(); 
  955.  
  956. // Activate this thing 
  957. if ( $activate ) { 
  958. try { 
  959. $result = activate_plugin( $plugin ); 
  960.  
  961. if ( is_wp_error( $result ) ) { 
  962. throw new Exception( $result->get_error_message() ); 
  963. } catch ( Exception $e ) { 
  964. WC_Admin_Notices::add_custom_notice( 
  965. $plugin_to_install_id . '_install_error',  
  966. sprintf( 
  967. __( '%1$s was installed but could not be activated. <a href="%2$s">Please activate it manually by clicking here.</a>', 'woocommerce' ),  
  968. $plugin_to_install['name'],  
  969. admin_url( 'plugins.php' ) 
  970. );