PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 3.0.9
WooCommerce v3.0.9
10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / includes / class-wc-install.php
woocommerce / includes Last commit date
abstracts 8 years ago admin 8 years ago api 8 years ago cli 8 years ago data-stores 8 years ago emails 8 years ago gateways 8 years ago interfaces 9 years ago legacy 9 years ago libraries 9 years ago log-handlers 9 years ago payment-tokens 9 years ago shipping 9 years ago shortcodes 8 years ago theme-support 9 years ago vendor 9 years ago walkers 9 years ago widgets 8 years ago class-wc-ajax.php 9 years ago class-wc-api.php 9 years ago class-wc-auth.php 9 years ago class-wc-autoloader.php 9 years ago class-wc-background-emailer.php 9 years ago class-wc-background-updater.php 9 years ago class-wc-breadcrumb.php 9 years ago class-wc-cache-helper.php 9 years ago class-wc-cart.php 8 years ago class-wc-checkout.php 8 years ago class-wc-cli.php 9 years ago class-wc-comments.php 9 years ago class-wc-countries.php 8 years ago class-wc-coupon.php 8 years ago class-wc-customer-download.php 9 years ago class-wc-customer.php 9 years ago class-wc-data-exception.php 9 years ago class-wc-data-store.php 9 years ago class-wc-datetime.php 9 years ago class-wc-deprecated-action-hooks.php 9 years ago class-wc-deprecated-filter-hooks.php 8 years ago class-wc-download-handler.php 9 years ago class-wc-emails.php 8 years ago class-wc-embed.php 9 years ago class-wc-form-handler.php 9 years ago class-wc-frontend-scripts.php 9 years ago class-wc-geo-ip.php 9 years ago class-wc-geolocation.php 8 years ago class-wc-https.php 9 years ago class-wc-install.php 9 years ago class-wc-integrations.php 9 years ago class-wc-legacy-api.php 9 years ago class-wc-log-levels.php 9 years ago class-wc-logger.php 9 years ago class-wc-order-factory.php 9 years ago class-wc-order-item-coupon.php 9 years ago class-wc-order-item-fee.php 9 years ago class-wc-order-item-meta.php 8 years ago class-wc-order-item-product.php 8 years ago class-wc-order-item-shipping.php 8 years ago class-wc-order-item-tax.php 9 years ago class-wc-order-item.php 8 years ago class-wc-order-refund.php 9 years ago class-wc-order.php 9 years ago class-wc-payment-gateways.php 9 years ago class-wc-payment-tokens.php 9 years ago class-wc-post-data.php 8 years ago class-wc-post-types.php 9 years ago class-wc-product-attribute.php 8 years ago class-wc-product-download.php 9 years ago class-wc-product-external.php 9 years ago class-wc-product-factory.php 9 years ago class-wc-product-grouped.php 8 years ago class-wc-product-simple.php 9 years ago class-wc-product-variable.php 8 years ago class-wc-product-variation.php 8 years ago class-wc-query.php 9 years ago class-wc-register-wp-admin-settings.php 9 years ago class-wc-session-handler.php 9 years ago class-wc-shipping-rate.php 9 years ago class-wc-shipping-zone.php 8 years ago class-wc-shipping-zones.php 9 years ago class-wc-shipping.php 9 years ago class-wc-shortcodes.php 8 years ago class-wc-structured-data.php 8 years ago class-wc-tax.php 9 years ago class-wc-template-loader.php 9 years ago class-wc-tracker.php 9 years ago class-wc-validation.php 9 years ago class-wc-webhook.php 8 years ago wc-account-functions.php 9 years ago wc-attribute-functions.php 9 years ago wc-cart-functions.php 9 years ago wc-conditional-functions.php 9 years ago wc-core-functions.php 8 years ago wc-coupon-functions.php 9 years ago wc-deprecated-functions.php 9 years ago wc-formatting-functions.php 9 years ago wc-notice-functions.php 9 years ago wc-order-functions.php 8 years ago wc-order-item-functions.php 8 years ago wc-page-functions.php 9 years ago wc-product-functions.php 8 years ago wc-rest-functions.php 8 years ago wc-stock-functions.php 9 years ago wc-template-functions.php 8 years ago wc-template-hooks.php 9 years ago wc-term-functions.php 9 years ago wc-update-functions.php 9 years ago wc-user-functions.php 9 years ago wc-webhook-functions.php 9 years ago wc-widget-functions.php 9 years ago
class-wc-install.php
1091 lines
1 <?php
2 /**
3 * Installation related functions and actions.
4 *
5 * @author WooThemes
6 * @category Admin
7 * @package WooCommerce/Classes
8 * @version 3.0.0
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 and callbacks that need to be run per version */
21 private static $db_updates = array(
22 '2.0.0' => array(
23 'wc_update_200_file_paths',
24 'wc_update_200_permalinks',
25 'wc_update_200_subcat_display',
26 'wc_update_200_taxrates',
27 'wc_update_200_line_items',
28 'wc_update_200_images',
29 'wc_update_200_db_version',
30 ),
31 '2.0.9' => array(
32 'wc_update_209_brazillian_state',
33 'wc_update_209_db_version',
34 ),
35 '2.1.0' => array(
36 'wc_update_210_remove_pages',
37 'wc_update_210_file_paths',
38 'wc_update_210_db_version',
39 ),
40 '2.2.0' => array(
41 'wc_update_220_shipping',
42 'wc_update_220_order_status',
43 'wc_update_220_variations',
44 'wc_update_220_attributes',
45 'wc_update_220_db_version',
46 ),
47 '2.3.0' => array(
48 'wc_update_230_options',
49 'wc_update_230_db_version',
50 ),
51 '2.4.0' => array(
52 'wc_update_240_options',
53 'wc_update_240_shipping_methods',
54 'wc_update_240_api_keys',
55 'wc_update_240_webhooks',
56 'wc_update_240_refunds',
57 'wc_update_240_db_version',
58 ),
59 '2.4.1' => array(
60 'wc_update_241_variations',
61 'wc_update_241_db_version',
62 ),
63 '2.5.0' => array(
64 'wc_update_250_currency',
65 'wc_update_250_db_version',
66 ),
67 '2.6.0' => array(
68 'wc_update_260_options',
69 'wc_update_260_termmeta',
70 'wc_update_260_zones',
71 'wc_update_260_zone_methods',
72 'wc_update_260_refunds',
73 'wc_update_260_db_version',
74 ),
75 '3.0.0' => array(
76 'wc_update_300_webhooks',
77 'wc_update_300_grouped_products',
78 'wc_update_300_settings',
79 'wc_update_300_product_visibility',
80 'wc_update_300_db_version',
81 ),
82 );
83
84 /** @var object Background update class */
85 private static $background_updater;
86
87 /**
88 * Hook in tabs.
89 */
90 public static function init() {
91 add_action( 'init', array( __CLASS__, 'check_version' ), 5 );
92 add_action( 'init', array( __CLASS__, 'init_background_updater' ), 5 );
93 add_action( 'admin_init', array( __CLASS__, 'install_actions' ) );
94 add_action( 'in_plugin_update_message-woocommerce/woocommerce.php', array( __CLASS__, 'in_plugin_update_message' ) );
95 add_filter( 'plugin_action_links_' . WC_PLUGIN_BASENAME, array( __CLASS__, 'plugin_action_links' ) );
96 add_filter( 'plugin_row_meta', array( __CLASS__, 'plugin_row_meta' ), 10, 2 );
97 add_filter( 'wpmu_drop_tables', array( __CLASS__, 'wpmu_drop_tables' ) );
98 add_filter( 'cron_schedules', array( __CLASS__, 'cron_schedules' ) );
99 add_action( 'woocommerce_plugin_background_installer', array( __CLASS__, 'background_installer' ), 10, 2 );
100 }
101
102 /**
103 * Init background updates
104 */
105 public static function init_background_updater() {
106 include_once( dirname( __FILE__ ) . '/class-wc-background-updater.php' );
107 self::$background_updater = new WC_Background_Updater();
108 }
109
110 /**
111 * Check WooCommerce version and run the updater is required.
112 *
113 * This check is done on all requests and runs if he versions do not match.
114 */
115 public static function check_version() {
116 if ( ! defined( 'IFRAME_REQUEST' ) && get_option( 'woocommerce_version' ) !== WC()->version ) {
117 self::install();
118 do_action( 'woocommerce_updated' );
119 }
120 }
121
122 /**
123 * Install actions when a update button is clicked within the admin area.
124 *
125 * This function is hooked into admin_init to affect admin only.
126 */
127 public static function install_actions() {
128 if ( ! empty( $_GET['do_update_woocommerce'] ) ) {
129 self::update();
130 WC_Admin_Notices::add_notice( 'update' );
131 }
132 if ( ! empty( $_GET['force_update_woocommerce'] ) ) {
133 do_action( 'wp_wc_updater_cron' );
134 wp_safe_redirect( admin_url( 'admin.php?page=wc-settings' ) );
135 exit;
136 }
137 }
138
139 /**
140 * Install WC.
141 */
142 public static function install() {
143 global $wpdb;
144
145 if ( ! is_blog_installed() ) {
146 return;
147 }
148
149 if ( ! defined( 'WC_INSTALLING' ) ) {
150 define( 'WC_INSTALLING', true );
151 }
152
153 // Ensure needed classes are loaded
154 include_once( dirname( __FILE__ ) . '/admin/class-wc-admin-notices.php' );
155
156 self::create_options();
157 self::create_tables();
158 self::create_roles();
159
160 // Register post types
161 WC_Post_types::register_post_types();
162 WC_Post_types::register_taxonomies();
163
164 // Also register endpoints - this needs to be done prior to rewrite rule flush
165 WC()->query->init_query_vars();
166 WC()->query->add_endpoints();
167 WC_API::add_endpoint();
168 WC_Auth::add_endpoint();
169
170 self::create_terms();
171 self::create_cron_jobs();
172 self::create_files();
173
174 // Queue upgrades/setup wizard
175 $current_wc_version = get_option( 'woocommerce_version', null );
176 $current_db_version = get_option( 'woocommerce_db_version', null );
177
178 WC_Admin_Notices::remove_all_notices();
179
180 // No versions? This is a new install :)
181 if ( is_null( $current_wc_version ) && is_null( $current_db_version ) && apply_filters( 'woocommerce_enable_setup_wizard', true ) ) {
182 WC_Admin_Notices::add_notice( 'install' );
183 set_transient( '_wc_activation_redirect', 1, 30 );
184
185 // No page? Let user run wizard again..
186 } elseif ( ! get_option( 'woocommerce_cart_page_id' ) ) {
187 WC_Admin_Notices::add_notice( 'install' );
188 }
189
190 if ( ! is_null( $current_db_version ) && version_compare( $current_db_version, max( array_keys( self::$db_updates ) ), '<' ) ) {
191 WC_Admin_Notices::add_notice( 'update' );
192 } else {
193 self::update_db_version();
194 }
195
196 self::update_wc_version();
197
198 // Flush rules after install
199 do_action( 'woocommerce_flush_rewrite_rules' );
200 delete_transient( 'wc_attribute_taxonomies' );
201
202 /*
203 * Deletes all expired transients. The multi-table delete syntax is used
204 * to delete the transient record from table a, and the corresponding
205 * transient_timeout record from table b.
206 *
207 * Based on code inside core's upgrade_network() function.
208 */
209 $sql = "DELETE a, b FROM $wpdb->options a, $wpdb->options b
210 WHERE a.option_name LIKE %s
211 AND a.option_name NOT LIKE %s
212 AND b.option_name = CONCAT( '_transient_timeout_', SUBSTRING( a.option_name, 12 ) )
213 AND b.option_value < %d";
214 $wpdb->query( $wpdb->prepare( $sql, $wpdb->esc_like( '_transient_' ) . '%', $wpdb->esc_like( '_transient_timeout_' ) . '%', time() ) );
215
216 // Trigger action
217 do_action( 'woocommerce_installed' );
218 }
219
220 /**
221 * Update WC version to current.
222 */
223 private static function update_wc_version() {
224 delete_option( 'woocommerce_version' );
225 add_option( 'woocommerce_version', WC()->version );
226 }
227
228 /**
229 * Get list of DB update callbacks.
230 *
231 * @since 3.0.0
232 * @return array
233 */
234 public static function get_db_update_callbacks() {
235 return self::$db_updates;
236 }
237
238 /**
239 * Push all needed DB updates to the queue for processing.
240 */
241 private static function update() {
242 $current_db_version = get_option( 'woocommerce_db_version' );
243 $logger = wc_get_logger();
244 $update_queued = false;
245
246 foreach ( self::get_db_update_callbacks() as $version => $update_callbacks ) {
247 if ( version_compare( $current_db_version, $version, '<' ) ) {
248 foreach ( $update_callbacks as $update_callback ) {
249 $logger->info(
250 sprintf( 'Queuing %s - %s', $version, $update_callback ),
251 array( 'source' => 'wc_db_updates' )
252 );
253 self::$background_updater->push_to_queue( $update_callback );
254 $update_queued = true;
255 }
256 }
257 }
258
259 if ( $update_queued ) {
260 self::$background_updater->save()->dispatch();
261 }
262 }
263
264 /**
265 * Update DB version to current.
266 * @param string $version
267 */
268 public static function update_db_version( $version = null ) {
269 delete_option( 'woocommerce_db_version' );
270 add_option( 'woocommerce_db_version', is_null( $version ) ? WC()->version : $version );
271 }
272
273 /**
274 * Add more cron schedules.
275 * @param array $schedules
276 * @return array
277 */
278 public static function cron_schedules( $schedules ) {
279 $schedules['monthly'] = array(
280 'interval' => 2635200,
281 'display' => __( 'Monthly', 'woocommerce' ),
282 );
283 return $schedules;
284 }
285
286 /**
287 * Create cron jobs (clear them first).
288 */
289 private static function create_cron_jobs() {
290 wp_clear_scheduled_hook( 'woocommerce_scheduled_sales' );
291 wp_clear_scheduled_hook( 'woocommerce_cancel_unpaid_orders' );
292 wp_clear_scheduled_hook( 'woocommerce_cleanup_sessions' );
293 wp_clear_scheduled_hook( 'woocommerce_geoip_updater' );
294 wp_clear_scheduled_hook( 'woocommerce_tracker_send_event' );
295
296 $ve = get_option( 'gmt_offset' ) > 0 ? '-' : '+';
297
298 wp_schedule_event( strtotime( '00:00 tomorrow ' . $ve . get_option( 'gmt_offset' ) . ' HOURS' ), 'daily', 'woocommerce_scheduled_sales' );
299
300 $held_duration = get_option( 'woocommerce_hold_stock_minutes', '60' );
301
302 if ( '' != $held_duration ) {
303 wp_schedule_single_event( time() + ( absint( $held_duration ) * 60 ), 'woocommerce_cancel_unpaid_orders' );
304 }
305
306 wp_schedule_event( time(), 'twicedaily', 'woocommerce_cleanup_sessions' );
307 wp_schedule_event( strtotime( 'first tuesday of next month' ), 'monthly', 'woocommerce_geoip_updater' );
308 wp_schedule_event( time(), apply_filters( 'woocommerce_tracker_event_recurrence', 'daily' ), 'woocommerce_tracker_send_event' );
309 }
310
311 /**
312 * Create pages that the plugin relies on, storing page IDs in variables.
313 */
314 public static function create_pages() {
315 include_once( dirname( __FILE__ ) . '/admin/wc-admin-functions.php' );
316
317 $pages = apply_filters( 'woocommerce_create_pages', array(
318 'shop' => array(
319 'name' => _x( 'shop', 'Page slug', 'woocommerce' ),
320 'title' => _x( 'Shop', 'Page title', 'woocommerce' ),
321 'content' => '',
322 ),
323 'cart' => array(
324 'name' => _x( 'cart', 'Page slug', 'woocommerce' ),
325 'title' => _x( 'Cart', 'Page title', 'woocommerce' ),
326 'content' => '[' . apply_filters( 'woocommerce_cart_shortcode_tag', 'woocommerce_cart' ) . ']',
327 ),
328 'checkout' => array(
329 'name' => _x( 'checkout', 'Page slug', 'woocommerce' ),
330 'title' => _x( 'Checkout', 'Page title', 'woocommerce' ),
331 'content' => '[' . apply_filters( 'woocommerce_checkout_shortcode_tag', 'woocommerce_checkout' ) . ']',
332 ),
333 'myaccount' => array(
334 'name' => _x( 'my-account', 'Page slug', 'woocommerce' ),
335 'title' => _x( 'My account', 'Page title', 'woocommerce' ),
336 'content' => '[' . apply_filters( 'woocommerce_my_account_shortcode_tag', 'woocommerce_my_account' ) . ']',
337 ),
338 ) );
339
340 foreach ( $pages as $key => $page ) {
341 wc_create_page( esc_sql( $page['name'] ), 'woocommerce_' . $key . '_page_id', $page['title'], $page['content'], ! empty( $page['parent'] ) ? wc_get_page_id( $page['parent'] ) : '' );
342 }
343
344 delete_transient( 'woocommerce_cache_excluded_uris' );
345 }
346
347 /**
348 * Default options.
349 *
350 * Sets up the default options used on the settings page.
351 */
352 private static function create_options() {
353 // Include settings so that we can run through defaults
354 include_once( dirname( __FILE__ ) . '/admin/class-wc-admin-settings.php' );
355
356 $settings = WC_Admin_Settings::get_settings_pages();
357
358 foreach ( $settings as $section ) {
359 if ( ! method_exists( $section, 'get_settings' ) ) {
360 continue;
361 }
362 $subsections = array_unique( array_merge( array( '' ), array_keys( $section->get_sections() ) ) );
363
364 foreach ( $subsections as $subsection ) {
365 foreach ( $section->get_settings( $subsection ) as $value ) {
366 if ( isset( $value['default'] ) && isset( $value['id'] ) ) {
367 $autoload = isset( $value['autoload'] ) ? (bool) $value['autoload'] : true;
368 add_option( $value['id'], $value['default'], '', ( $autoload ? 'yes' : 'no' ) );
369 }
370 }
371 }
372 }
373 }
374
375 /**
376 * Add the default terms for WC taxonomies - product types and order statuses. Modify this at your own risk.
377 */
378 public static function create_terms() {
379 $taxonomies = array(
380 'product_type' => array(
381 'simple',
382 'grouped',
383 'variable',
384 'external',
385 ),
386 'product_visibility' => array(
387 'exclude-from-search',
388 'exclude-from-catalog',
389 'featured',
390 'outofstock',
391 'rated-1',
392 'rated-2',
393 'rated-3',
394 'rated-4',
395 'rated-5',
396 ),
397 );
398
399 foreach ( $taxonomies as $taxonomy => $terms ) {
400 foreach ( $terms as $term ) {
401 if ( ! get_term_by( 'name', $term, $taxonomy ) ) {
402 wp_insert_term( $term, $taxonomy );
403 }
404 }
405 }
406 }
407
408 /**
409 * Set up the database tables which the plugin needs to function.
410 *
411 * Tables:
412 * woocommerce_attribute_taxonomies - Table for storing attribute taxonomies - these are user defined
413 * woocommerce_termmeta - Term meta table - sadly WordPress does not have termmeta so we need our own
414 * woocommerce_downloadable_product_permissions - Table for storing user and guest download permissions.
415 * KEY(order_id, product_id, download_id) used for organizing downloads on the My Account page
416 * woocommerce_order_items - Order line items are stored in a table to make them easily queryable for reports
417 * woocommerce_order_itemmeta - Order line item meta is stored in a table for storing extra data.
418 * woocommerce_tax_rates - Tax Rates are stored inside 2 tables making tax queries simple and efficient.
419 * woocommerce_tax_rate_locations - Each rate can be applied to more than one postcode/city hence the second table.
420 */
421 private static function create_tables() {
422 global $wpdb;
423
424 $wpdb->hide_errors();
425
426 require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
427
428 /**
429 * Before updating with DBDELTA, remove any primary keys which could be
430 * modified due to schema updates.
431 */
432 if ( $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->prefix}woocommerce_downloadable_product_permissions';" ) ) {
433 if ( ! $wpdb->get_var( "SHOW COLUMNS FROM `{$wpdb->prefix}woocommerce_downloadable_product_permissions` LIKE 'permission_id';" ) ) {
434 $wpdb->query( "ALTER TABLE {$wpdb->prefix}woocommerce_downloadable_product_permissions DROP PRIMARY KEY, ADD `permission_id` BIGINT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT;" );
435 }
436 }
437
438 dbDelta( self::get_schema() );
439
440 $index_exists = $wpdb->get_row( "SHOW INDEX FROM {$wpdb->comments} WHERE column_name = 'comment_type' and key_name = 'woo_idx_comment_type'" );
441
442 if ( is_null( $index_exists ) ) {
443 // Add an index to the field comment_type to improve the response time of the query
444 // used by WC_Comments::wp_count_comments() to get the number of comments by type.
445 $wpdb->query( "ALTER TABLE {$wpdb->comments} ADD INDEX woo_idx_comment_type (comment_type)" );
446 }
447 }
448
449 /**
450 * Get Table schema.
451 *
452 * https://github.com/woocommerce/woocommerce/wiki/Database-Description/
453 *
454 * A note on indexes; Indexes have a maximum size of 767 bytes. Historically, we haven't need to be concerned about that.
455 * As of WordPress 4.2, however, we moved to utf8mb4, which uses 4 bytes per character. This means that an index which
456 * used to have room for floor(767/3) = 255 characters, now only has room for floor(767/4) = 191 characters.
457 *
458 * Changing indexes may cause duplicate index notices in logs due to https://core.trac.wordpress.org/ticket/34870 but dropping
459 * indexes first causes too much load on some servers/larger DB.
460 *
461 * @return string
462 */
463 private static function get_schema() {
464 global $wpdb;
465
466 $collate = '';
467
468 if ( $wpdb->has_cap( 'collation' ) ) {
469 $collate = $wpdb->get_charset_collate();
470 }
471
472 $tables = "
473 CREATE TABLE {$wpdb->prefix}woocommerce_sessions (
474 session_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
475 session_key char(32) NOT NULL,
476 session_value longtext NOT NULL,
477 session_expiry BIGINT UNSIGNED NOT NULL,
478 PRIMARY KEY (session_key),
479 UNIQUE KEY session_id (session_id)
480 ) $collate;
481 CREATE TABLE {$wpdb->prefix}woocommerce_api_keys (
482 key_id BIGINT UNSIGNED NOT NULL auto_increment,
483 user_id BIGINT UNSIGNED NOT NULL,
484 description varchar(200) NULL,
485 permissions varchar(10) NOT NULL,
486 consumer_key char(64) NOT NULL,
487 consumer_secret char(43) NOT NULL,
488 nonces longtext NULL,
489 truncated_key char(7) NOT NULL,
490 last_access datetime NULL default null,
491 PRIMARY KEY (key_id),
492 KEY consumer_key (consumer_key),
493 KEY consumer_secret (consumer_secret)
494 ) $collate;
495 CREATE TABLE {$wpdb->prefix}woocommerce_attribute_taxonomies (
496 attribute_id BIGINT UNSIGNED NOT NULL auto_increment,
497 attribute_name varchar(200) NOT NULL,
498 attribute_label varchar(200) NULL,
499 attribute_type varchar(20) NOT NULL,
500 attribute_orderby varchar(20) NOT NULL,
501 attribute_public int(1) NOT NULL DEFAULT 1,
502 PRIMARY KEY (attribute_id),
503 KEY attribute_name (attribute_name(20))
504 ) $collate;
505 CREATE TABLE {$wpdb->prefix}woocommerce_downloadable_product_permissions (
506 permission_id BIGINT UNSIGNED NOT NULL auto_increment,
507 download_id varchar(32) NOT NULL,
508 product_id BIGINT UNSIGNED NOT NULL,
509 order_id BIGINT UNSIGNED NOT NULL DEFAULT 0,
510 order_key varchar(200) NOT NULL,
511 user_email varchar(200) NOT NULL,
512 user_id BIGINT UNSIGNED NULL,
513 downloads_remaining varchar(9) NULL,
514 access_granted datetime NOT NULL default '0000-00-00 00:00:00',
515 access_expires datetime NULL default null,
516 download_count BIGINT UNSIGNED NOT NULL DEFAULT 0,
517 PRIMARY KEY (permission_id),
518 KEY download_order_key_product (product_id,order_id,order_key(16),download_id),
519 KEY download_order_product (download_id,order_id,product_id)
520 ) $collate;
521 CREATE TABLE {$wpdb->prefix}woocommerce_order_items (
522 order_item_id BIGINT UNSIGNED NOT NULL auto_increment,
523 order_item_name TEXT NOT NULL,
524 order_item_type varchar(200) NOT NULL DEFAULT '',
525 order_id BIGINT UNSIGNED NOT NULL,
526 PRIMARY KEY (order_item_id),
527 KEY order_id (order_id)
528 ) $collate;
529 CREATE TABLE {$wpdb->prefix}woocommerce_order_itemmeta (
530 meta_id BIGINT UNSIGNED NOT NULL auto_increment,
531 order_item_id BIGINT UNSIGNED NOT NULL,
532 meta_key varchar(255) default NULL,
533 meta_value longtext NULL,
534 PRIMARY KEY (meta_id),
535 KEY order_item_id (order_item_id),
536 KEY meta_key (meta_key(32))
537 ) $collate;
538 CREATE TABLE {$wpdb->prefix}woocommerce_tax_rates (
539 tax_rate_id BIGINT UNSIGNED NOT NULL auto_increment,
540 tax_rate_country varchar(2) NOT NULL DEFAULT '',
541 tax_rate_state varchar(200) NOT NULL DEFAULT '',
542 tax_rate varchar(8) NOT NULL DEFAULT '',
543 tax_rate_name varchar(200) NOT NULL DEFAULT '',
544 tax_rate_priority BIGINT UNSIGNED NOT NULL,
545 tax_rate_compound int(1) NOT NULL DEFAULT 0,
546 tax_rate_shipping int(1) NOT NULL DEFAULT 1,
547 tax_rate_order BIGINT UNSIGNED NOT NULL,
548 tax_rate_class varchar(200) NOT NULL DEFAULT '',
549 PRIMARY KEY (tax_rate_id),
550 KEY tax_rate_country (tax_rate_country),
551 KEY tax_rate_state (tax_rate_state(2)),
552 KEY tax_rate_class (tax_rate_class(10)),
553 KEY tax_rate_priority (tax_rate_priority)
554 ) $collate;
555 CREATE TABLE {$wpdb->prefix}woocommerce_tax_rate_locations (
556 location_id BIGINT UNSIGNED NOT NULL auto_increment,
557 location_code varchar(200) NOT NULL,
558 tax_rate_id BIGINT UNSIGNED NOT NULL,
559 location_type varchar(40) NOT NULL,
560 PRIMARY KEY (location_id),
561 KEY tax_rate_id (tax_rate_id),
562 KEY location_type_code (location_type(10),location_code(20))
563 ) $collate;
564 CREATE TABLE {$wpdb->prefix}woocommerce_shipping_zones (
565 zone_id BIGINT UNSIGNED NOT NULL auto_increment,
566 zone_name varchar(200) NOT NULL,
567 zone_order BIGINT UNSIGNED NOT NULL,
568 PRIMARY KEY (zone_id)
569 ) $collate;
570 CREATE TABLE {$wpdb->prefix}woocommerce_shipping_zone_locations (
571 location_id BIGINT UNSIGNED NOT NULL auto_increment,
572 zone_id BIGINT UNSIGNED NOT NULL,
573 location_code varchar(200) NOT NULL,
574 location_type varchar(40) NOT NULL,
575 PRIMARY KEY (location_id),
576 KEY location_id (location_id),
577 KEY location_type_code (location_type(10),location_code(20))
578 ) $collate;
579 CREATE TABLE {$wpdb->prefix}woocommerce_shipping_zone_methods (
580 zone_id BIGINT UNSIGNED NOT NULL,
581 instance_id BIGINT UNSIGNED NOT NULL auto_increment,
582 method_id varchar(200) NOT NULL,
583 method_order BIGINT UNSIGNED NOT NULL,
584 is_enabled tinyint(1) NOT NULL DEFAULT '1',
585 PRIMARY KEY (instance_id)
586 ) $collate;
587 CREATE TABLE {$wpdb->prefix}woocommerce_payment_tokens (
588 token_id BIGINT UNSIGNED NOT NULL auto_increment,
589 gateway_id varchar(200) NOT NULL,
590 token text NOT NULL,
591 user_id BIGINT UNSIGNED NOT NULL DEFAULT '0',
592 type varchar(200) NOT NULL,
593 is_default tinyint(1) NOT NULL DEFAULT '0',
594 PRIMARY KEY (token_id),
595 KEY user_id (user_id)
596 ) $collate;
597 CREATE TABLE {$wpdb->prefix}woocommerce_payment_tokenmeta (
598 meta_id BIGINT UNSIGNED NOT NULL auto_increment,
599 payment_token_id BIGINT UNSIGNED NOT NULL,
600 meta_key varchar(255) NULL,
601 meta_value longtext NULL,
602 PRIMARY KEY (meta_id),
603 KEY payment_token_id (payment_token_id),
604 KEY meta_key (meta_key(32))
605 ) $collate;
606 CREATE TABLE {$wpdb->prefix}woocommerce_log (
607 log_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
608 timestamp datetime NOT NULL,
609 level smallint(4) NOT NULL,
610 source varchar(200) NOT NULL,
611 message longtext NOT NULL,
612 context longtext NULL,
613 PRIMARY KEY (log_id),
614 KEY level (level)
615 ) $collate;
616 ";
617
618 /**
619 * Term meta is only needed for old installs and is now @deprecated by WordPress term meta.
620 */
621 if ( ! function_exists( 'get_term_meta' ) ) {
622 $tables .= "
623 CREATE TABLE {$wpdb->prefix}woocommerce_termmeta (
624 meta_id BIGINT UNSIGNED NOT NULL auto_increment,
625 woocommerce_term_id BIGINT UNSIGNED NOT NULL,
626 meta_key varchar(255) default NULL,
627 meta_value longtext NULL,
628 PRIMARY KEY (meta_id),
629 KEY woocommerce_term_id (woocommerce_term_id),
630 KEY meta_key (meta_key(32))
631 ) $collate;
632 ";
633 }
634
635 return $tables;
636 }
637
638 /**
639 * Create roles and capabilities.
640 */
641 public static function create_roles() {
642 global $wp_roles;
643
644 if ( ! class_exists( 'WP_Roles' ) ) {
645 return;
646 }
647
648 if ( ! isset( $wp_roles ) ) {
649 $wp_roles = new WP_Roles();
650 }
651
652 // Customer role
653 add_role( 'customer', __( 'Customer', 'woocommerce' ), array(
654 'read' => true,
655 ) );
656
657 // Shop manager role
658 add_role( 'shop_manager', __( 'Shop manager', 'woocommerce' ), array(
659 'level_9' => true,
660 'level_8' => true,
661 'level_7' => true,
662 'level_6' => true,
663 'level_5' => true,
664 'level_4' => true,
665 'level_3' => true,
666 'level_2' => true,
667 'level_1' => true,
668 'level_0' => true,
669 'read' => true,
670 'read_private_pages' => true,
671 'read_private_posts' => true,
672 'edit_users' => true,
673 'edit_posts' => true,
674 'edit_pages' => true,
675 'edit_published_posts' => true,
676 'edit_published_pages' => true,
677 'edit_private_pages' => true,
678 'edit_private_posts' => true,
679 'edit_others_posts' => true,
680 'edit_others_pages' => true,
681 'publish_posts' => true,
682 'publish_pages' => true,
683 'delete_posts' => true,
684 'delete_pages' => true,
685 'delete_private_pages' => true,
686 'delete_private_posts' => true,
687 'delete_published_pages' => true,
688 'delete_published_posts' => true,
689 'delete_others_posts' => true,
690 'delete_others_pages' => true,
691 'manage_categories' => true,
692 'manage_links' => true,
693 'moderate_comments' => true,
694 'unfiltered_html' => true,
695 'upload_files' => true,
696 'export' => true,
697 'import' => true,
698 'list_users' => true,
699 ) );
700
701 $capabilities = self::get_core_capabilities();
702
703 foreach ( $capabilities as $cap_group ) {
704 foreach ( $cap_group as $cap ) {
705 $wp_roles->add_cap( 'shop_manager', $cap );
706 $wp_roles->add_cap( 'administrator', $cap );
707 }
708 }
709 }
710
711 /**
712 * Get capabilities for WooCommerce - these are assigned to admin/shop manager during installation or reset.
713 *
714 * @return array
715 */
716 private static function get_core_capabilities() {
717 $capabilities = array();
718
719 $capabilities['core'] = array(
720 'manage_woocommerce',
721 'view_woocommerce_reports',
722 );
723
724 $capability_types = array( 'product', 'shop_order', 'shop_coupon', 'shop_webhook' );
725
726 foreach ( $capability_types as $capability_type ) {
727
728 $capabilities[ $capability_type ] = array(
729 // Post type
730 "edit_{$capability_type}",
731 "read_{$capability_type}",
732 "delete_{$capability_type}",
733 "edit_{$capability_type}s",
734 "edit_others_{$capability_type}s",
735 "publish_{$capability_type}s",
736 "read_private_{$capability_type}s",
737 "delete_{$capability_type}s",
738 "delete_private_{$capability_type}s",
739 "delete_published_{$capability_type}s",
740 "delete_others_{$capability_type}s",
741 "edit_private_{$capability_type}s",
742 "edit_published_{$capability_type}s",
743
744 // Terms
745 "manage_{$capability_type}_terms",
746 "edit_{$capability_type}_terms",
747 "delete_{$capability_type}_terms",
748 "assign_{$capability_type}_terms",
749 );
750 }
751
752 return $capabilities;
753 }
754
755 /**
756 * woocommerce_remove_roles function.
757 */
758 public static function remove_roles() {
759 global $wp_roles;
760
761 if ( ! class_exists( 'WP_Roles' ) ) {
762 return;
763 }
764
765 if ( ! isset( $wp_roles ) ) {
766 $wp_roles = new WP_Roles();
767 }
768
769 $capabilities = self::get_core_capabilities();
770
771 foreach ( $capabilities as $cap_group ) {
772 foreach ( $cap_group as $cap ) {
773 $wp_roles->remove_cap( 'shop_manager', $cap );
774 $wp_roles->remove_cap( 'administrator', $cap );
775 }
776 }
777
778 remove_role( 'customer' );
779 remove_role( 'shop_manager' );
780 }
781
782 /**
783 * Create files/directories.
784 */
785 private static function create_files() {
786 // Install files and folders for uploading files and prevent hotlinking
787 $upload_dir = wp_upload_dir();
788 $download_method = get_option( 'woocommerce_file_download_method', 'force' );
789
790 $files = array(
791 array(
792 'base' => $upload_dir['basedir'] . '/woocommerce_uploads',
793 'file' => 'index.html',
794 'content' => '',
795 ),
796 array(
797 'base' => WC_LOG_DIR,
798 'file' => '.htaccess',
799 'content' => 'deny from all',
800 ),
801 array(
802 'base' => WC_LOG_DIR,
803 'file' => 'index.html',
804 'content' => '',
805 ),
806 );
807
808 if ( 'redirect' !== $download_method ) {
809 $files[] = array(
810 'base' => $upload_dir['basedir'] . '/woocommerce_uploads',
811 'file' => '.htaccess',
812 'content' => 'deny from all',
813 );
814 }
815
816 foreach ( $files as $file ) {
817 if ( wp_mkdir_p( $file['base'] ) && ! file_exists( trailingslashit( $file['base'] ) . $file['file'] ) ) {
818 if ( $file_handle = @fopen( trailingslashit( $file['base'] ) . $file['file'], 'w' ) ) {
819 fwrite( $file_handle, $file['content'] );
820 fclose( $file_handle );
821 }
822 }
823 }
824 }
825
826 /**
827 * Show plugin changes. Code adapted from W3 Total Cache.
828 */
829 public static function in_plugin_update_message( $args ) {
830 $transient_name = 'wc_upgrade_notice_' . $args['Version'];
831
832 if ( false === ( $upgrade_notice = get_transient( $transient_name ) ) ) {
833 $response = wp_safe_remote_get( 'https://plugins.svn.wordpress.org/woocommerce/trunk/readme.txt' );
834
835 if ( ! is_wp_error( $response ) && ! empty( $response['body'] ) ) {
836 $upgrade_notice = self::parse_update_notice( $response['body'], $args['new_version'] );
837 set_transient( $transient_name, $upgrade_notice, DAY_IN_SECONDS );
838 }
839 }
840
841 echo wp_kses_post( $upgrade_notice );
842 }
843
844 /**
845 * Parse update notice from readme file.
846 *
847 * @param string $content
848 * @param string $new_version
849 * @return string
850 */
851 private static function parse_update_notice( $content, $new_version ) {
852 // Output Upgrade Notice.
853 $matches = null;
854 $regexp = '~==\s*Upgrade Notice\s*==\s*=\s*(.*)\s*=(.*)(=\s*' . preg_quote( WC_VERSION ) . '\s*=|$)~Uis';
855 $upgrade_notice = '';
856
857 if ( preg_match( $regexp, $content, $matches ) ) {
858 $notices = (array) preg_split( '~[\r\n]+~', trim( $matches[2] ) );
859
860 // Convert the full version strings to minor versions.
861 $notice_version_parts = explode( '.', trim( $matches[1] ) );
862 $current_version_parts = explode( '.', WC_VERSION );
863
864 if ( 3 !== sizeof( $notice_version_parts ) ) {
865 return;
866 }
867
868 $notice_version = $notice_version_parts[0] . '.' . $notice_version_parts[1];
869 $current_version = $current_version_parts[0] . '.' . $current_version_parts[1];
870
871 // Check the latest stable version and ignore trunk.
872 if ( version_compare( $current_version, $notice_version, '<' ) ) {
873
874 $upgrade_notice .= '</p><p class="wc_plugin_upgrade_notice">';
875
876 foreach ( $notices as $index => $line ) {
877 $upgrade_notice .= preg_replace( '~\[([^\]]*)\]\(([^\)]*)\)~', '<a href="${2}">${1}</a>', $line );
878 }
879 }
880 }
881
882 return wp_kses_post( $upgrade_notice );
883 }
884
885 /**
886 * Show action links on the plugin screen.
887 *
888 * @param mixed $links Plugin Action links
889 * @return array
890 */
891 public static function plugin_action_links( $links ) {
892 $action_links = array(
893 'settings' => '<a href="' . admin_url( 'admin.php?page=wc-settings' ) . '" aria-label="' . esc_attr__( 'View WooCommerce settings', 'woocommerce' ) . '">' . esc_html__( 'Settings', 'woocommerce' ) . '</a>',
894 );
895
896 return array_merge( $action_links, $links );
897 }
898
899 /**
900 * Show row meta on the plugin screen.
901 *
902 * @param mixed $links Plugin Row Meta
903 * @param mixed $file Plugin Base file
904 * @return array
905 */
906 public static function plugin_row_meta( $links, $file ) {
907 if ( WC_PLUGIN_BASENAME == $file ) {
908 $row_meta = array(
909 '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>',
910 '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>',
911 '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>',
912 );
913
914 return array_merge( $links, $row_meta );
915 }
916
917 return (array) $links;
918 }
919
920 /**
921 * Uninstall tables when MU blog is deleted.
922 * @param array $tables
923 * @return string[]
924 */
925 public static function wpmu_drop_tables( $tables ) {
926 global $wpdb;
927
928 $tables[] = $wpdb->prefix . 'woocommerce_sessions';
929 $tables[] = $wpdb->prefix . 'woocommerce_api_keys';
930 $tables[] = $wpdb->prefix . 'woocommerce_attribute_taxonomies';
931 $tables[] = $wpdb->prefix . 'woocommerce_downloadable_product_permissions';
932 $tables[] = $wpdb->prefix . 'woocommerce_termmeta';
933 $tables[] = $wpdb->prefix . 'woocommerce_tax_rates';
934 $tables[] = $wpdb->prefix . 'woocommerce_tax_rate_locations';
935 $tables[] = $wpdb->prefix . 'woocommerce_order_items';
936 $tables[] = $wpdb->prefix . 'woocommerce_order_itemmeta';
937 $tables[] = $wpdb->prefix . 'woocommerce_payment_tokens';
938 $tables[] = $wpdb->prefix . 'woocommerce_shipping_zones';
939 $tables[] = $wpdb->prefix . 'woocommerce_shipping_zone_locations';
940 $tables[] = $wpdb->prefix . 'woocommerce_shipping_zone_methods';
941
942 return $tables;
943 }
944
945 /**
946 * Get slug from path
947 * @param string $key
948 * @return string
949 */
950 private static function format_plugin_slug( $key ) {
951 $slug = explode( '/', $key );
952 $slug = explode( '.', end( $slug ) );
953 return $slug[0];
954 }
955
956 /**
957 * Install a plugin from .org in the background via a cron job (used by
958 * installer - opt in).
959 * @param string $plugin_to_install_id
960 * @param array $plugin_to_install
961 * @since 2.6.0
962 */
963 public static function background_installer( $plugin_to_install_id, $plugin_to_install ) {
964 // Explicitly clear the event.
965 wp_clear_scheduled_hook( 'woocommerce_plugin_background_installer', func_get_args() );
966
967 if ( ! empty( $plugin_to_install['repo-slug'] ) ) {
968 require_once( ABSPATH . 'wp-admin/includes/file.php' );
969 require_once( ABSPATH . 'wp-admin/includes/plugin-install.php' );
970 require_once( ABSPATH . 'wp-admin/includes/class-wp-upgrader.php' );
971 require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
972
973 WP_Filesystem();
974
975 $skin = new Automatic_Upgrader_Skin;
976 $upgrader = new WP_Upgrader( $skin );
977 $installed_plugins = array_map( array( __CLASS__, 'format_plugin_slug' ), array_keys( get_plugins() ) );
978 $plugin_slug = $plugin_to_install['repo-slug'];
979 $plugin = $plugin_slug . '/' . $plugin_slug . '.php';
980 $installed = false;
981 $activate = false;
982
983 // See if the plugin is installed already
984 if ( in_array( $plugin_to_install['repo-slug'], $installed_plugins ) ) {
985 $installed = true;
986 $activate = ! is_plugin_active( $plugin );
987 }
988
989 // Install this thing!
990 if ( ! $installed ) {
991 // Suppress feedback
992 ob_start();
993
994 try {
995 $plugin_information = plugins_api( 'plugin_information', array(
996 'slug' => $plugin_to_install['repo-slug'],
997 'fields' => array(
998 'short_description' => false,
999 'sections' => false,
1000 'requires' => false,
1001 'rating' => false,
1002 'ratings' => false,
1003 'downloaded' => false,
1004 'last_updated' => false,
1005 'added' => false,
1006 'tags' => false,
1007 'homepage' => false,
1008 'donate_link' => false,
1009 'author_profile' => false,
1010 'author' => false,
1011 ),
1012 ) );
1013
1014 if ( is_wp_error( $plugin_information ) ) {
1015 throw new Exception( $plugin_information->get_error_message() );
1016 }
1017
1018 $package = $plugin_information->download_link;
1019 $download = $upgrader->download_package( $package );
1020
1021 if ( is_wp_error( $download ) ) {
1022 throw new Exception( $download->get_error_message() );
1023 }
1024
1025 $working_dir = $upgrader->unpack_package( $download, true );
1026
1027 if ( is_wp_error( $working_dir ) ) {
1028 throw new Exception( $working_dir->get_error_message() );
1029 }
1030
1031 $result = $upgrader->install_package( array(
1032 'source' => $working_dir,
1033 'destination' => WP_PLUGIN_DIR,
1034 'clear_destination' => false,
1035 'abort_if_destination_exists' => false,
1036 'clear_working' => true,
1037 'hook_extra' => array(
1038 'type' => 'plugin',
1039 'action' => 'install',
1040 ),
1041 ) );
1042
1043 if ( is_wp_error( $result ) ) {
1044 throw new Exception( $result->get_error_message() );
1045 }
1046
1047 $activate = true;
1048
1049 } catch ( Exception $e ) {
1050 WC_Admin_Notices::add_custom_notice(
1051 $plugin_to_install_id . '_install_error',
1052 sprintf(
1053 __( '%1$s could not be installed (%2$s). <a href="%3$s">Please install it manually by clicking here.</a>', 'woocommerce' ),
1054 $plugin_to_install['name'],
1055 $e->getMessage(),
1056 esc_url( admin_url( 'index.php?wc-install-plugin-redirect=' . $plugin_to_install['repo-slug'] ) )
1057 )
1058 );
1059 }
1060
1061 // Discard feedback
1062 ob_end_clean();
1063 }
1064
1065 wp_clean_plugins_cache();
1066
1067 // Activate this thing
1068 if ( $activate ) {
1069 try {
1070 $result = activate_plugin( $plugin );
1071
1072 if ( is_wp_error( $result ) ) {
1073 throw new Exception( $result->get_error_message() );
1074 }
1075 } catch ( Exception $e ) {
1076 WC_Admin_Notices::add_custom_notice(
1077 $plugin_to_install_id . '_install_error',
1078 sprintf(
1079 __( '%1$s was installed but could not be activated. <a href="%2$s">Please activate it manually by clicking here.</a>', 'woocommerce' ),
1080 $plugin_to_install['name'],
1081 admin_url( 'plugins.php' )
1082 )
1083 );
1084 }
1085 }
1086 }
1087 }
1088 }
1089
1090 WC_Install::init();
1091