PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 7.5.1
WooCommerce v7.5.1
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 3 years ago admin 3 years ago blocks 5 years ago cli 3 years ago customizer 3 years ago data-stores 3 years ago emails 3 years ago export 3 years ago gateways 3 years ago import 3 years ago integrations 4 years ago interfaces 3 years ago legacy 3 years ago libraries 3 years ago log-handlers 4 years ago payment-tokens 5 years ago queue 4 years ago react-admin 3 years ago rest-api 3 years ago shipping 4 years ago shortcodes 3 years ago theme-support 3 years ago tracks 3 years ago traits 5 years ago walkers 5 years ago wccom-site 5 years ago widgets 4 years ago class-wc-ajax.php 3 years ago class-wc-api.php 4 years ago class-wc-auth.php 4 years ago class-wc-autoloader.php 5 years ago class-wc-background-emailer.php 5 years ago class-wc-background-updater.php 5 years ago class-wc-breadcrumb.php 5 years ago class-wc-cache-helper.php 4 years ago class-wc-cart-fees.php 5 years ago class-wc-cart-session.php 3 years ago class-wc-cart-totals.php 4 years ago class-wc-cart.php 3 years ago class-wc-checkout.php 3 years ago class-wc-cli.php 3 years ago class-wc-comments.php 3 years ago class-wc-countries.php 3 years ago class-wc-coupon.php 4 years ago class-wc-customer-download-log.php 5 years ago class-wc-customer-download.php 4 years ago class-wc-customer.php 4 years ago class-wc-data-exception.php 8 years ago class-wc-data-store.php 3 years ago class-wc-datetime.php 4 years ago class-wc-deprecated-action-hooks.php 8 years ago class-wc-deprecated-filter-hooks.php 3 years ago class-wc-discounts.php 3 years ago class-wc-download-handler.php 3 years ago class-wc-emails.php 3 years ago class-wc-embed.php 5 years ago class-wc-form-handler.php 4 years ago class-wc-frontend-scripts.php 3 years ago class-wc-geo-ip.php 4 years ago class-wc-geolite-integration.php 6 years ago class-wc-geolocation.php 3 years ago class-wc-https.php 4 years ago class-wc-install.php 3 years ago class-wc-integrations.php 5 years ago class-wc-log-levels.php 5 years ago class-wc-logger.php 4 years ago class-wc-meta-data.php 4 years ago class-wc-order-factory.php 3 years ago class-wc-order-item-coupon.php 4 years ago class-wc-order-item-fee.php 4 years ago class-wc-order-item-meta.php 4 years ago class-wc-order-item-product.php 4 years ago class-wc-order-item-shipping.php 4 years ago class-wc-order-item-tax.php 4 years ago class-wc-order-item.php 4 years ago class-wc-order-query.php 4 years ago class-wc-order-refund.php 3 years ago class-wc-order.php 3 years ago class-wc-payment-gateways.php 4 years ago class-wc-payment-tokens.php 3 years ago class-wc-post-data.php 3 years ago class-wc-post-types.php 3 years ago class-wc-privacy-background-process.php 5 years ago class-wc-privacy-erasers.php 4 years ago class-wc-privacy-exporters.php 4 years ago class-wc-privacy.php 4 years ago class-wc-product-attribute.php 4 years ago class-wc-product-download.php 4 years ago class-wc-product-external.php 5 years ago class-wc-product-factory.php 5 years ago class-wc-product-grouped.php 8 years ago class-wc-product-query.php 5 years ago class-wc-product-simple.php 3 years ago class-wc-product-variable.php 4 years ago class-wc-product-variation.php 4 years ago class-wc-query.php 3 years ago class-wc-rate-limiter.php 4 years ago class-wc-regenerate-images-request.php 3 years ago class-wc-regenerate-images.php 3 years ago class-wc-register-wp-admin-settings.php 4 years ago class-wc-rest-authentication.php 5 years ago class-wc-rest-exception.php 5 years ago class-wc-session-handler.php 3 years ago class-wc-shipping-rate.php 3 years ago class-wc-shipping-zone.php 5 years ago class-wc-shipping-zones.php 5 years ago class-wc-shipping.php 4 years ago class-wc-shortcodes.php 5 years ago class-wc-structured-data.php 5 years ago class-wc-tax.php 4 years ago class-wc-template-loader.php 3 years ago class-wc-tracker.php 3 years ago class-wc-validation.php 3 years ago class-wc-webhook.php 3 years ago class-woocommerce.php 3 years ago wc-account-functions.php 3 years ago wc-attribute-functions.php 3 years ago wc-cart-functions.php 3 years ago wc-conditional-functions.php 3 years ago wc-core-functions.php 3 years ago wc-coupon-functions.php 5 years ago wc-deprecated-functions.php 3 years ago wc-formatting-functions.php 3 years ago wc-notice-functions.php 5 years ago wc-order-functions.php 3 years ago wc-order-item-functions.php 3 years ago wc-page-functions.php 5 years ago wc-product-functions.php 3 years ago wc-rest-functions.php 3 years ago wc-stock-functions.php 4 years ago wc-template-functions.php 3 years ago wc-template-hooks.php 5 years ago wc-term-functions.php 3 years ago wc-update-functions.php 3 years ago wc-user-functions.php 3 years ago wc-webhook-functions.php 4 years ago wc-widget-functions.php 5 years ago
class-wc-install.php
2299 lines
1 <?php
2 /**
3 * Installation related functions and actions.
4 *
5 * @package WooCommerce\Classes
6 * @version 3.0.0
7 */
8
9 use Automattic\Jetpack\Constants;
10 use Automattic\WooCommerce\Admin\Notes\Notes;
11 use Automattic\WooCommerce\Internal\ProductAttributesLookup\DataRegenerator;
12 use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Register as Download_Directories;
13 use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Synchronize as Download_Directories_Sync;
14 use Automattic\WooCommerce\Internal\Utilities\DatabaseUtil;
15 use Automattic\WooCommerce\Internal\WCCom\ConnectionHelper as WCConnectionHelper;
16
17 defined( 'ABSPATH' ) || exit;
18
19 /**
20 * WC_Install Class.
21 */
22 class WC_Install {
23
24 /**
25 * DB updates and callbacks that need to be run per version.
26 *
27 * Please note that these functions are invoked when WooCommerce is updated from a previous version,
28 * but NOT when WooCommerce is newly installed.
29 *
30 * Database schema changes must be incorporated to the SQL returned by get_schema, which is applied
31 * via dbDelta at both install and update time. If any other kind of database change is required
32 * at install time (e.g. populating tables), use the 'woocommerce_installed' hook.
33 *
34 * @var array
35 */
36 private static $db_updates = array(
37 '2.0.0' => array(
38 'wc_update_200_file_paths',
39 'wc_update_200_permalinks',
40 'wc_update_200_subcat_display',
41 'wc_update_200_taxrates',
42 'wc_update_200_line_items',
43 'wc_update_200_images',
44 'wc_update_200_db_version',
45 ),
46 '2.0.9' => array(
47 'wc_update_209_brazillian_state',
48 'wc_update_209_db_version',
49 ),
50 '2.1.0' => array(
51 'wc_update_210_remove_pages',
52 'wc_update_210_file_paths',
53 'wc_update_210_db_version',
54 ),
55 '2.2.0' => array(
56 'wc_update_220_shipping',
57 'wc_update_220_order_status',
58 'wc_update_220_variations',
59 'wc_update_220_attributes',
60 'wc_update_220_db_version',
61 ),
62 '2.3.0' => array(
63 'wc_update_230_options',
64 'wc_update_230_db_version',
65 ),
66 '2.4.0' => array(
67 'wc_update_240_options',
68 'wc_update_240_shipping_methods',
69 'wc_update_240_api_keys',
70 'wc_update_240_refunds',
71 'wc_update_240_db_version',
72 ),
73 '2.4.1' => array(
74 'wc_update_241_variations',
75 'wc_update_241_db_version',
76 ),
77 '2.5.0' => array(
78 'wc_update_250_currency',
79 'wc_update_250_db_version',
80 ),
81 '2.6.0' => array(
82 'wc_update_260_options',
83 'wc_update_260_termmeta',
84 'wc_update_260_zones',
85 'wc_update_260_zone_methods',
86 'wc_update_260_refunds',
87 'wc_update_260_db_version',
88 ),
89 '3.0.0' => array(
90 'wc_update_300_grouped_products',
91 'wc_update_300_settings',
92 'wc_update_300_product_visibility',
93 'wc_update_300_db_version',
94 ),
95 '3.1.0' => array(
96 'wc_update_310_downloadable_products',
97 'wc_update_310_old_comments',
98 'wc_update_310_db_version',
99 ),
100 '3.1.2' => array(
101 'wc_update_312_shop_manager_capabilities',
102 'wc_update_312_db_version',
103 ),
104 '3.2.0' => array(
105 'wc_update_320_mexican_states',
106 'wc_update_320_db_version',
107 ),
108 '3.3.0' => array(
109 'wc_update_330_image_options',
110 'wc_update_330_webhooks',
111 'wc_update_330_product_stock_status',
112 'wc_update_330_set_default_product_cat',
113 'wc_update_330_clear_transients',
114 'wc_update_330_set_paypal_sandbox_credentials',
115 'wc_update_330_db_version',
116 ),
117 '3.4.0' => array(
118 'wc_update_340_states',
119 'wc_update_340_state',
120 'wc_update_340_last_active',
121 'wc_update_340_db_version',
122 ),
123 '3.4.3' => array(
124 'wc_update_343_cleanup_foreign_keys',
125 'wc_update_343_db_version',
126 ),
127 '3.4.4' => array(
128 'wc_update_344_recreate_roles',
129 'wc_update_344_db_version',
130 ),
131 '3.5.0' => array(
132 'wc_update_350_reviews_comment_type',
133 'wc_update_350_db_version',
134 ),
135 '3.5.2' => array(
136 'wc_update_352_drop_download_log_fk',
137 ),
138 '3.5.4' => array(
139 'wc_update_354_modify_shop_manager_caps',
140 'wc_update_354_db_version',
141 ),
142 '3.6.0' => array(
143 'wc_update_360_product_lookup_tables',
144 'wc_update_360_term_meta',
145 'wc_update_360_downloadable_product_permissions_index',
146 'wc_update_360_db_version',
147 ),
148 '3.7.0' => array(
149 'wc_update_370_tax_rate_classes',
150 'wc_update_370_mro_std_currency',
151 'wc_update_370_db_version',
152 ),
153 '3.9.0' => array(
154 'wc_update_390_move_maxmind_database',
155 'wc_update_390_change_geolocation_database_update_cron',
156 'wc_update_390_db_version',
157 ),
158 '4.0.0' => array(
159 'wc_update_product_lookup_tables',
160 'wc_update_400_increase_size_of_column',
161 'wc_update_400_reset_action_scheduler_migration_status',
162 'wc_admin_update_0201_order_status_index',
163 'wc_admin_update_0230_rename_gross_total',
164 'wc_admin_update_0251_remove_unsnooze_action',
165 'wc_update_400_db_version',
166 ),
167 '4.4.0' => array(
168 'wc_update_440_insert_attribute_terms_for_variable_products',
169 'wc_admin_update_110_remove_facebook_note',
170 'wc_admin_update_130_remove_dismiss_action_from_tracking_opt_in_note',
171 'wc_update_440_db_version',
172 ),
173 '4.5.0' => array(
174 'wc_update_450_sanitize_coupons_code',
175 'wc_update_450_db_version',
176 ),
177 '5.0.0' => array(
178 'wc_update_500_fix_product_review_count',
179 'wc_admin_update_160_remove_facebook_note',
180 'wc_admin_update_170_homescreen_layout',
181 'wc_update_500_db_version',
182 ),
183 '5.6.0' => array(
184 'wc_update_560_create_refund_returns_page',
185 'wc_update_560_db_version',
186 ),
187 '6.0.0' => array(
188 'wc_update_600_migrate_rate_limit_options',
189 'wc_admin_update_270_delete_report_downloads',
190 'wc_admin_update_271_update_task_list_options',
191 'wc_admin_update_280_order_status',
192 'wc_admin_update_290_update_apperance_task_option',
193 'wc_admin_update_290_delete_default_homepage_layout_option',
194 'wc_update_600_db_version',
195 ),
196 '6.3.0' => array(
197 'wc_update_630_create_product_attributes_lookup_table',
198 'wc_admin_update_300_update_is_read_from_last_read',
199 'wc_update_630_db_version',
200 ),
201 '6.4.0' => array(
202 'wc_update_640_add_primary_key_to_product_attributes_lookup_table',
203 'wc_admin_update_340_remove_is_primary_from_note_action',
204 'wc_update_640_db_version',
205 ),
206 '6.5.0' => array(
207 'wc_update_650_approved_download_directories',
208 ),
209 '6.5.1' => array(
210 'wc_update_651_approved_download_directories',
211 ),
212 '6.7.0' => array(
213 'wc_update_670_purge_comments_count_cache',
214 'wc_update_670_delete_deprecated_remote_inbox_notifications_option',
215 ),
216 '7.0.0' => array(
217 'wc_update_700_remove_download_log_fk',
218 'wc_update_700_remove_recommended_marketing_plugins_transient',
219 ),
220 '7.2.1' => array(
221 'wc_update_721_adjust_new_zealand_states',
222 'wc_update_721_adjust_ukraine_states',
223 ),
224 '7.2.2' => array(
225 'wc_update_722_adjust_new_zealand_states',
226 'wc_update_722_adjust_ukraine_states',
227 ),
228 '7.5.0' => array(
229 'wc_update_750_add_columns_to_order_stats_table',
230 'wc_update_750_disable_new_product_management_experience',
231 ),
232 );
233
234 /**
235 * Hook in tabs.
236 */
237 public static function init() {
238 add_action( 'init', array( __CLASS__, 'check_version' ), 5 );
239 add_action( 'init', array( __CLASS__, 'manual_database_update' ), 20 );
240 add_action( 'admin_init', array( __CLASS__, 'wc_admin_db_update_notice' ) );
241 add_action( 'admin_init', array( __CLASS__, 'add_admin_note_after_page_created' ) );
242 add_action( 'woocommerce_run_update_callback', array( __CLASS__, 'run_update_callback' ) );
243 add_action( 'woocommerce_update_db_to_current_version', array( __CLASS__, 'update_db_version' ) );
244 add_action( 'admin_init', array( __CLASS__, 'install_actions' ) );
245 add_action( 'woocommerce_page_created', array( __CLASS__, 'page_created' ), 10, 2 );
246 add_filter( 'plugin_action_links_' . WC_PLUGIN_BASENAME, array( __CLASS__, 'plugin_action_links' ) );
247 add_filter( 'plugin_row_meta', array( __CLASS__, 'plugin_row_meta' ), 10, 2 );
248 add_filter( 'wpmu_drop_tables', array( __CLASS__, 'wpmu_drop_tables' ) );
249 add_filter( 'cron_schedules', array( __CLASS__, 'cron_schedules' ) );
250 }
251
252 /**
253 * Check WooCommerce version and run the updater is required.
254 *
255 * This check is done on all requests and runs if the versions do not match.
256 */
257 public static function check_version() {
258 $wc_version = get_option( 'woocommerce_version' );
259 $wc_code_version = WC()->version;
260 $requires_update = version_compare( $wc_version, $wc_code_version, '<' );
261 if ( ! Constants::is_defined( 'IFRAME_REQUEST' ) && $requires_update ) {
262 self::install();
263 /**
264 * Run after WooCommerce has been updated.
265 *
266 * @since 2.2.0
267 */
268 do_action( 'woocommerce_updated' );
269 do_action_deprecated( 'woocommerce_admin_updated', array(), $wc_code_version, 'woocommerce_updated' );
270 // If there is no woocommerce_version option, consider it as a new install.
271 if ( ! $wc_version ) {
272 /**
273 * Run when WooCommerce has been installed for the first time.
274 *
275 * @since 6.5.0
276 */
277 do_action( 'woocommerce_newly_installed' );
278 do_action_deprecated( 'woocommerce_admin_newly_installed', array(), $wc_code_version, 'woocommerce_newly_installed' );
279 }
280 }
281 }
282
283 /**
284 * Performan manual database update when triggered by WooCommerce System Tools.
285 *
286 * @since 3.6.5
287 */
288 public static function manual_database_update() {
289 $blog_id = get_current_blog_id();
290
291 add_action( 'wp_' . $blog_id . '_wc_updater_cron', array( __CLASS__, 'run_manual_database_update' ) );
292 }
293
294 /**
295 * Add WC Admin based db update notice.
296 *
297 * @since 4.0.0
298 */
299 public static function wc_admin_db_update_notice() {
300 if (
301 WC()->is_wc_admin_active() &&
302 false !== get_option( 'woocommerce_admin_install_timestamp' )
303 ) {
304 new WC_Notes_Run_Db_Update();
305 }
306 }
307
308 /**
309 * Run manual database update.
310 */
311 public static function run_manual_database_update() {
312 self::update();
313 }
314
315 /**
316 * Run an update callback when triggered by ActionScheduler.
317 *
318 * @param string $update_callback Callback name.
319 *
320 * @since 3.6.0
321 */
322 public static function run_update_callback( $update_callback ) {
323 include_once dirname( __FILE__ ) . '/wc-update-functions.php';
324
325 if ( is_callable( $update_callback ) ) {
326 self::run_update_callback_start( $update_callback );
327 $result = (bool) call_user_func( $update_callback );
328 self::run_update_callback_end( $update_callback, $result );
329 }
330 }
331
332 /**
333 * Triggered when a callback will run.
334 *
335 * @since 3.6.0
336 * @param string $callback Callback name.
337 */
338 protected static function run_update_callback_start( $callback ) {
339 wc_maybe_define_constant( 'WC_UPDATING', true );
340 }
341
342 /**
343 * Triggered when a callback has ran.
344 *
345 * @since 3.6.0
346 * @param string $callback Callback name.
347 * @param bool $result Return value from callback. Non-false need to run again.
348 */
349 protected static function run_update_callback_end( $callback, $result ) {
350 if ( $result ) {
351 WC()->queue()->add(
352 'woocommerce_run_update_callback',
353 array(
354 'update_callback' => $callback,
355 ),
356 'woocommerce-db-updates'
357 );
358 }
359 }
360
361 /**
362 * Install actions when a update button is clicked within the admin area.
363 *
364 * This function is hooked into admin_init to affect admin only.
365 */
366 public static function install_actions() {
367 if ( ! empty( $_GET['do_update_woocommerce'] ) ) { // WPCS: input var ok.
368 check_admin_referer( 'wc_db_update', 'wc_db_update_nonce' );
369 self::update();
370 WC_Admin_Notices::add_notice( 'update', true );
371 }
372 }
373
374 /**
375 * Install WC.
376 */
377 public static function install() {
378 if ( ! is_blog_installed() ) {
379 return;
380 }
381
382 // Check if we are not already running this routine.
383 if ( self::is_installing() ) {
384 return;
385 }
386
387 // If we made it till here nothing is running yet, lets set the transient now.
388 set_transient( 'wc_installing', 'yes', MINUTE_IN_SECONDS * 10 );
389 wc_maybe_define_constant( 'WC_INSTALLING', true );
390
391 WC()->wpdb_table_fix();
392 self::remove_admin_notices();
393 self::create_tables();
394 self::verify_base_tables();
395 self::create_options();
396 self::migrate_options();
397 self::create_roles();
398 self::setup_environment();
399 self::create_terms();
400 self::create_cron_jobs();
401 self::delete_obsolete_notes();
402 self::create_files();
403 self::maybe_create_pages();
404 self::maybe_set_activation_transients();
405 self::set_paypal_standard_load_eligibility();
406 self::update_wc_version();
407 self::maybe_update_db_version();
408
409 delete_transient( 'wc_installing' );
410
411 // Use add_option() here to avoid overwriting this value with each
412 // plugin version update. We base plugin age off of this value.
413 add_option( 'woocommerce_admin_install_timestamp', time() );
414
415 /**
416 * Flush the rewrite rules after install or update.
417 *
418 * @since 2.7.0
419 */
420 do_action( 'woocommerce_flush_rewrite_rules' );
421 /**
422 * Run after WooCommerce has been installed or updated.
423 *
424 * @since 3.2.0
425 */
426 do_action( 'woocommerce_installed' );
427 /**
428 * Run after WooCommerce Admin has been installed or updated.
429 *
430 * @since 6.5.0
431 */
432 do_action( 'woocommerce_admin_installed' );
433 }
434
435 /**
436 * Returns true if we're installing.
437 *
438 * @return bool
439 */
440 private static function is_installing() {
441 return 'yes' === get_transient( 'wc_installing' );
442 }
443
444 /**
445 * Check if all the base tables are present.
446 *
447 * @param bool $modify_notice Whether to modify notice based on if all tables are present.
448 * @param bool $execute Whether to execute get_schema queries as well.
449 *
450 * @return array List of queries.
451 */
452 public static function verify_base_tables( $modify_notice = true, $execute = false ) {
453 if ( $execute ) {
454 self::create_tables();
455 }
456
457 $missing_tables = wc_get_container()
458 ->get( DatabaseUtil::class )
459 ->get_missing_tables( self::get_schema() );
460
461 if ( 0 < count( $missing_tables ) ) {
462 if ( $modify_notice ) {
463 WC_Admin_Notices::add_notice( 'base_tables_missing' );
464 }
465 update_option( 'woocommerce_schema_missing_tables', $missing_tables );
466 } else {
467 if ( $modify_notice ) {
468 WC_Admin_Notices::remove_notice( 'base_tables_missing' );
469 }
470 update_option( 'woocommerce_schema_version', WC()->db_version );
471 delete_option( 'woocommerce_schema_missing_tables' );
472 }
473 return $missing_tables;
474 }
475
476 /**
477 * Reset any notices added to admin.
478 *
479 * @since 3.2.0
480 */
481 private static function remove_admin_notices() {
482 include_once dirname( __FILE__ ) . '/admin/class-wc-admin-notices.php';
483 WC_Admin_Notices::remove_all_notices();
484 }
485
486 /**
487 * Setup WC environment - post types, taxonomies, endpoints.
488 *
489 * @since 3.2.0
490 */
491 private static function setup_environment() {
492 WC_Post_types::register_post_types();
493 WC_Post_types::register_taxonomies();
494 WC()->query->init_query_vars();
495 WC()->query->add_endpoints();
496 WC_API::add_endpoint();
497 WC_Auth::add_endpoint();
498 }
499
500 /**
501 * Is this a brand new WC install?
502 *
503 * A brand new install has no version yet. Also treat empty installs as 'new'.
504 *
505 * @since 3.2.0
506 * @return boolean
507 */
508 public static function is_new_install() {
509 $product_count = array_sum( (array) wp_count_posts( 'product' ) );
510
511 return is_null( get_option( 'woocommerce_version', null ) ) || ( 0 === $product_count && -1 === wc_get_page_id( 'shop' ) );
512 }
513
514 /**
515 * Is a DB update needed?
516 *
517 * @since 3.2.0
518 * @return boolean
519 */
520 public static function needs_db_update() {
521 $current_db_version = get_option( 'woocommerce_db_version', null );
522 $updates = self::get_db_update_callbacks();
523 $update_versions = array_keys( $updates );
524 usort( $update_versions, 'version_compare' );
525
526 return ! is_null( $current_db_version ) && version_compare( $current_db_version, end( $update_versions ), '<' );
527 }
528
529 /**
530 * See if we need to set redirect transients for activation or not.
531 *
532 * @since 4.6.0
533 */
534 private static function maybe_set_activation_transients() {
535 if ( self::is_new_install() ) {
536 set_transient( '_wc_activation_redirect', 1, 30 );
537 }
538 }
539
540 /**
541 * See if we need to show or run database updates during install.
542 *
543 * @since 3.2.0
544 */
545 private static function maybe_update_db_version() {
546 if ( self::needs_db_update() ) {
547 /**
548 * Allow WooCommerce to auto-update without prompting the user.
549 *
550 * @since 3.2.0
551 */
552 if ( apply_filters( 'woocommerce_enable_auto_update_db', false ) ) {
553 self::update();
554 } else {
555 WC_Admin_Notices::add_notice( 'update', true );
556 }
557 } else {
558 self::update_db_version();
559 }
560 }
561
562 /**
563 * Update WC version to current.
564 */
565 private static function update_wc_version() {
566 update_option( 'woocommerce_version', WC()->version );
567 }
568
569 /**
570 * Get list of DB update callbacks.
571 *
572 * @since 3.0.0
573 * @return array
574 */
575 public static function get_db_update_callbacks() {
576 return self::$db_updates;
577 }
578
579 /**
580 * Push all needed DB updates to the queue for processing.
581 */
582 private static function update() {
583 $current_db_version = get_option( 'woocommerce_db_version' );
584 $loop = 0;
585
586 foreach ( self::get_db_update_callbacks() as $version => $update_callbacks ) {
587 if ( version_compare( $current_db_version, $version, '<' ) ) {
588 foreach ( $update_callbacks as $update_callback ) {
589 WC()->queue()->schedule_single(
590 time() + $loop,
591 'woocommerce_run_update_callback',
592 array(
593 'update_callback' => $update_callback,
594 ),
595 'woocommerce-db-updates'
596 );
597 $loop++;
598 }
599 }
600 }
601
602 // After the callbacks finish, update the db version to the current WC version.
603 $current_wc_version = WC()->version;
604 if ( version_compare( $current_db_version, $current_wc_version, '<' ) &&
605 ! WC()->queue()->get_next( 'woocommerce_update_db_to_current_version' ) ) {
606 WC()->queue()->schedule_single(
607 time() + $loop,
608 'woocommerce_update_db_to_current_version',
609 array(
610 'version' => $current_wc_version,
611 ),
612 'woocommerce-db-updates'
613 );
614 }
615 }
616
617 /**
618 * Update DB version to current.
619 *
620 * @param string|null $version New WooCommerce DB version or null.
621 */
622 public static function update_db_version( $version = null ) {
623 update_option( 'woocommerce_db_version', is_null( $version ) ? WC()->version : $version );
624 }
625
626 /**
627 * Add more cron schedules.
628 *
629 * @param array $schedules List of WP scheduled cron jobs.
630 *
631 * @return array
632 */
633 public static function cron_schedules( $schedules ) {
634 $schedules['monthly'] = array(
635 'interval' => 2635200,
636 'display' => __( 'Monthly', 'woocommerce' ),
637 );
638 $schedules['fifteendays'] = array(
639 'interval' => 1296000,
640 'display' => __( 'Every 15 Days', 'woocommerce' ),
641 );
642 return $schedules;
643 }
644
645 /**
646 * Create cron jobs (clear them first).
647 */
648 private static function create_cron_jobs() {
649 wp_clear_scheduled_hook( 'woocommerce_scheduled_sales' );
650 wp_clear_scheduled_hook( 'woocommerce_cancel_unpaid_orders' );
651 wp_clear_scheduled_hook( 'woocommerce_cleanup_sessions' );
652 wp_clear_scheduled_hook( 'woocommerce_cleanup_personal_data' );
653 wp_clear_scheduled_hook( 'woocommerce_cleanup_logs' );
654 wp_clear_scheduled_hook( 'woocommerce_geoip_updater' );
655 wp_clear_scheduled_hook( 'woocommerce_tracker_send_event' );
656 wp_clear_scheduled_hook( 'woocommerce_cleanup_rate_limits' );
657
658 $ve = get_option( 'gmt_offset' ) > 0 ? '-' : '+';
659
660 wp_schedule_event( strtotime( '00:00 tomorrow ' . $ve . absint( get_option( 'gmt_offset' ) ) . ' HOURS' ), 'daily', 'woocommerce_scheduled_sales' );
661
662 $held_duration = get_option( 'woocommerce_hold_stock_minutes', '60' );
663
664 if ( '' !== $held_duration ) {
665 /**
666 * Determines the interval at which to cancel unpaid orders in minutes.
667 *
668 * @since 5.1.0
669 */
670 $cancel_unpaid_interval = apply_filters( 'woocommerce_cancel_unpaid_orders_interval_minutes', absint( $held_duration ) );
671 wp_schedule_single_event( time() + ( absint( $cancel_unpaid_interval ) * 60 ), 'woocommerce_cancel_unpaid_orders' );
672 }
673
674 // Delay the first run of `woocommerce_cleanup_personal_data` by 10 seconds
675 // so it doesn't occur in the same request. WooCommerce Admin also schedules
676 // a daily cron that gets lost due to a race condition. WC_Privacy's background
677 // processing instance updates the cron schedule from within a cron job.
678 wp_schedule_event( time() + 10, 'daily', 'woocommerce_cleanup_personal_data' );
679 wp_schedule_event( time() + ( 3 * HOUR_IN_SECONDS ), 'daily', 'woocommerce_cleanup_logs' );
680 wp_schedule_event( time() + ( 6 * HOUR_IN_SECONDS ), 'twicedaily', 'woocommerce_cleanup_sessions' );
681 wp_schedule_event( time() + MINUTE_IN_SECONDS, 'fifteendays', 'woocommerce_geoip_updater' );
682 /**
683 * How frequent to schedule the tracker send event.
684 *
685 * @since 2.3.0
686 */
687 wp_schedule_event( time() + 10, apply_filters( 'woocommerce_tracker_event_recurrence', 'daily' ), 'woocommerce_tracker_send_event' );
688 wp_schedule_event( time() + ( 3 * HOUR_IN_SECONDS ), 'daily', 'woocommerce_cleanup_rate_limits' );
689
690 if ( ! wp_next_scheduled( 'wc_admin_daily' ) ) {
691 wp_schedule_event( time(), 'daily', 'wc_admin_daily' );
692 }
693 // Note: this is potentially redundant when the core package exists.
694 wp_schedule_single_event( time() + 10, 'generate_category_lookup_table' );
695 }
696
697 /**
698 * Create pages on installation.
699 */
700 public static function maybe_create_pages() {
701 if ( empty( get_option( 'woocommerce_db_version' ) ) ) {
702 self::create_pages();
703 }
704 }
705
706 /**
707 * Create pages that the plugin relies on, storing page IDs in variables.
708 */
709 public static function create_pages() {
710 include_once dirname( __FILE__ ) . '/admin/wc-admin-functions.php';
711
712 /**
713 * Determines the cart shortcode tag used for the cart page.
714 *
715 * @since 2.1.0
716 */
717 $cart_shortcode = apply_filters( 'woocommerce_cart_shortcode_tag', 'woocommerce_cart' );
718
719 /**
720 * Determines the checkout shortcode tag used on the checkout page.
721 *
722 * @since 2.1.0
723 */
724 $checkout_shortcode = apply_filters( 'woocommerce_checkout_shortcode_tag', 'woocommerce_checkout' );
725
726 /**
727 * Determines the my account shortcode tag used on the my account page.
728 *
729 * @since 2.1.0
730 */
731 $my_account_shortcode = apply_filters( 'woocommerce_my_account_shortcode_tag', 'woocommerce_my_account' );
732
733 /**
734 * Determines which pages are created during install.
735 *
736 * @since 2.1.0
737 */
738 $pages = apply_filters(
739 'woocommerce_create_pages',
740 array(
741 'shop' => array(
742 'name' => _x( 'shop', 'Page slug', 'woocommerce' ),
743 'title' => _x( 'Shop', 'Page title', 'woocommerce' ),
744 'content' => '',
745 ),
746 'cart' => array(
747 'name' => _x( 'cart', 'Page slug', 'woocommerce' ),
748 'title' => _x( 'Cart', 'Page title', 'woocommerce' ),
749 'content' => '<!-- wp:shortcode -->[' . $cart_shortcode . ']<!-- /wp:shortcode -->',
750 ),
751 'checkout' => array(
752 'name' => _x( 'checkout', 'Page slug', 'woocommerce' ),
753 'title' => _x( 'Checkout', 'Page title', 'woocommerce' ),
754 'content' => '<!-- wp:shortcode -->[' . $checkout_shortcode . ']<!-- /wp:shortcode -->',
755 ),
756 'myaccount' => array(
757 'name' => _x( 'my-account', 'Page slug', 'woocommerce' ),
758 'title' => _x( 'My account', 'Page title', 'woocommerce' ),
759 'content' => '<!-- wp:shortcode -->[' . $my_account_shortcode . ']<!-- /wp:shortcode -->',
760 ),
761 'refund_returns' => array(
762 'name' => _x( 'refund_returns', 'Page slug', 'woocommerce' ),
763 'title' => _x( 'Refund and Returns Policy', 'Page title', 'woocommerce' ),
764 'content' => self::get_refunds_return_policy_page_content(),
765 'post_status' => 'draft',
766 ),
767 )
768 );
769
770 foreach ( $pages as $key => $page ) {
771 wc_create_page(
772 esc_sql( $page['name'] ),
773 'woocommerce_' . $key . '_page_id',
774 $page['title'],
775 $page['content'],
776 ! empty( $page['parent'] ) ? wc_get_page_id( $page['parent'] ) : '',
777 ! empty( $page['post_status'] ) ? $page['post_status'] : 'publish'
778 );
779 }
780 }
781
782 /**
783 * Default options.
784 *
785 * Sets up the default options used on the settings page.
786 */
787 private static function create_options() {
788 // Include settings so that we can run through defaults.
789 include_once dirname( __FILE__ ) . '/admin/class-wc-admin-settings.php';
790
791 $settings = WC_Admin_Settings::get_settings_pages();
792
793 foreach ( $settings as $section ) {
794 if ( ! is_a( $section, 'WC_Settings_Page' ) || ! method_exists( $section, 'get_settings' ) ) {
795 continue;
796 }
797 $subsections = array_unique( array_merge( array( '' ), array_keys( $section->get_sections() ) ) );
798
799 /**
800 * We are using 'WC_Settings_Page::get_settings' on purpose even thought it's deprecated.
801 * See the method documentation for an explanation.
802 */
803
804 foreach ( $subsections as $subsection ) {
805 foreach ( $section->get_settings( $subsection ) as $value ) {
806 if ( isset( $value['default'] ) && isset( $value['id'] ) ) {
807 $autoload = isset( $value['autoload'] ) ? (bool) $value['autoload'] : true;
808 add_option( $value['id'], $value['default'], '', ( $autoload ? 'yes' : 'no' ) );
809 }
810 }
811 }
812 }
813
814 // Define other defaults if not in setting screens.
815 add_option( 'woocommerce_single_image_width', '600', '', 'yes' );
816 add_option( 'woocommerce_thumbnail_image_width', '300', '', 'yes' );
817 add_option( 'woocommerce_checkout_highlight_required_fields', 'yes', '', 'yes' );
818 add_option( 'woocommerce_demo_store', 'no', '', 'no' );
819
820 if ( self::is_new_install() ) {
821 // Define initial tax classes.
822 WC_Tax::create_tax_class( __( 'Reduced rate', 'woocommerce' ) );
823 WC_Tax::create_tax_class( __( 'Zero rate', 'woocommerce' ) );
824
825 // For new installs, setup and enable Approved Product Download Directories.
826 wc_get_container()->get( Download_Directories_Sync::class )->init_feature( false, true );
827 }
828 }
829
830 /**
831 * Delete obsolete notes.
832 */
833 public static function delete_obsolete_notes() {
834 global $wpdb;
835 $obsolete_notes_names = array(
836 'wc-admin-welcome-note',
837 'wc-admin-insight-first-product-and-payment',
838 'wc-admin-store-notice-setting-moved',
839 'wc-admin-store-notice-giving-feedback',
840 'wc-admin-first-downloadable-product',
841 'wc-admin-learn-more-about-product-settings',
842 'wc-admin-adding-and-managing-products',
843 'wc-admin-onboarding-profiler-reminder',
844 'wc-admin-historical-data',
845 'wc-admin-manage-store-activity-from-home-screen',
846 'wc-admin-review-shipping-settings',
847 'wc-admin-home-screen-feedback',
848 'wc-admin-update-store-details',
849 'wc-admin-effortless-payments-by-mollie',
850 'wc-admin-google-ads-and-marketing',
851 'wc-admin-insight-first-sale',
852 'wc-admin-marketing-intro',
853 'wc-admin-draw-attention',
854 'wc-admin-welcome-to-woocommerce-for-store-users',
855 'wc-admin-need-some-inspiration',
856 'wc-admin-choose-niche',
857 'wc-admin-start-dropshipping-business',
858 'wc-admin-filter-by-product-variations-in-reports',
859 'wc-admin-learn-more-about-variable-products',
860 'wc-admin-getting-started-ecommerce-webinar',
861 'wc-admin-navigation-feedback',
862 'wc-admin-navigation-feedback-follow-up',
863 'wc-admin-set-up-additional-payment-types',
864 'wc-admin-deactivate-plugin',
865 'wc-admin-complete-store-details',
866 );
867
868 /**
869 * An array of deprecated notes to delete on update.
870 *
871 * @since 6.5.0
872 */
873 $additional_obsolete_notes_names = apply_filters(
874 'woocommerce_admin_obsolete_notes_names',
875 array()
876 );
877
878 if ( is_array( $additional_obsolete_notes_names ) ) {
879 $obsolete_notes_names = array_merge(
880 $obsolete_notes_names,
881 $additional_obsolete_notes_names
882 );
883 }
884
885 foreach ( $obsolete_notes_names as $obsolete_notes_name ) {
886 $wpdb->delete( $wpdb->prefix . 'wc_admin_notes', array( 'name' => $obsolete_notes_name ) );
887 $wpdb->delete( $wpdb->prefix . 'wc_admin_note_actions', array( 'name' => $obsolete_notes_name ) );
888 }
889 }
890
891 /**
892 * Migrate option values to their new keys/names.
893 */
894 public static function migrate_options() {
895
896 $migrated_options = array(
897 'woocommerce_onboarding_profile' => 'wc_onboarding_profile',
898 'woocommerce_admin_install_timestamp' => 'wc_admin_install_timestamp',
899 'woocommerce_onboarding_opt_in' => 'wc_onboarding_opt_in',
900 'woocommerce_admin_import_stats' => 'wc_admin_import_stats',
901 'woocommerce_admin_version' => 'wc_admin_version',
902 'woocommerce_admin_last_orders_milestone' => 'wc_admin_last_orders_milestone',
903 'woocommerce_admin-wc-helper-last-refresh' => 'wc-admin-wc-helper-last-refresh',
904 'woocommerce_admin_report_export_status' => 'wc_admin_report_export_status',
905 'woocommerce_task_list_complete' => 'woocommerce_task_list_complete',
906 'woocommerce_task_list_hidden' => 'woocommerce_task_list_hidden',
907 'woocommerce_extended_task_list_complete' => 'woocommerce_extended_task_list_complete',
908 'woocommerce_extended_task_list_hidden' => 'woocommerce_extended_task_list_hidden',
909 );
910
911 wc_maybe_define_constant( 'WC_ADMIN_MIGRATING_OPTIONS', true );
912
913 foreach ( $migrated_options as $new_option => $old_option ) {
914 $old_option_value = get_option( $old_option, false );
915
916 // Continue if no option value was previously set.
917 if ( false === $old_option_value ) {
918 continue;
919 }
920
921 if ( '1' === $old_option_value ) {
922 $old_option_value = 'yes';
923 } elseif ( '0' === $old_option_value ) {
924 $old_option_value = 'no';
925 }
926
927 update_option( $new_option, $old_option_value );
928 if ( $new_option !== $old_option ) {
929 delete_option( $old_option );
930 }
931 }
932 }
933 /**
934 * Add the default terms for WC taxonomies - product types and order statuses. Modify this at your own risk.
935 */
936 public static function create_terms() {
937 $taxonomies = array(
938 'product_type' => array(
939 'simple',
940 'grouped',
941 'variable',
942 'external',
943 ),
944 'product_visibility' => array(
945 'exclude-from-search',
946 'exclude-from-catalog',
947 'featured',
948 'outofstock',
949 'rated-1',
950 'rated-2',
951 'rated-3',
952 'rated-4',
953 'rated-5',
954 ),
955 );
956
957 foreach ( $taxonomies as $taxonomy => $terms ) {
958 foreach ( $terms as $term ) {
959 if ( ! get_term_by( 'name', $term, $taxonomy ) ) { // @codingStandardsIgnoreLine.
960 wp_insert_term( $term, $taxonomy );
961 }
962 }
963 }
964
965 $woocommerce_default_category = (int) get_option( 'default_product_cat', 0 );
966
967 if ( ! $woocommerce_default_category || ! term_exists( $woocommerce_default_category, 'product_cat' ) ) {
968 $default_product_cat_id = 0;
969 $default_product_cat_slug = sanitize_title( _x( 'Uncategorized', 'Default category slug', 'woocommerce' ) );
970 $default_product_cat = get_term_by( 'slug', $default_product_cat_slug, 'product_cat' ); // @codingStandardsIgnoreLine.
971
972 if ( $default_product_cat ) {
973 $default_product_cat_id = absint( $default_product_cat->term_taxonomy_id );
974 } else {
975 $result = wp_insert_term( _x( 'Uncategorized', 'Default category slug', 'woocommerce' ), 'product_cat', array( 'slug' => $default_product_cat_slug ) );
976
977 if ( ! is_wp_error( $result ) && ! empty( $result['term_taxonomy_id'] ) ) {
978 $default_product_cat_id = absint( $result['term_taxonomy_id'] );
979 }
980 }
981
982 if ( $default_product_cat_id ) {
983 update_option( 'default_product_cat', $default_product_cat_id );
984 }
985 }
986 }
987
988 /**
989 * Set up the database tables which the plugin needs to function.
990 * WARNING: If you are modifying this method, make sure that its safe to call regardless of the state of database.
991 *
992 * This is called from `install` method and is executed in-sync when WC is installed or updated. This can also be called optionally from `verify_base_tables`.
993 *
994 * TODO: Add all crucial tables that we have created from workers in the past.
995 *
996 * Tables:
997 * woocommerce_attribute_taxonomies - Table for storing attribute taxonomies - these are user defined
998 * woocommerce_downloadable_product_permissions - Table for storing user and guest download permissions.
999 * KEY(order_id, product_id, download_id) used for organizing downloads on the My Account page
1000 * woocommerce_order_items - Order line items are stored in a table to make them easily queryable for reports
1001 * woocommerce_order_itemmeta - Order line item meta is stored in a table for storing extra data.
1002 * woocommerce_tax_rates - Tax Rates are stored inside 2 tables making tax queries simple and efficient.
1003 * woocommerce_tax_rate_locations - Each rate can be applied to more than one postcode/city hence the second table.
1004 *
1005 * @return array Strings containing the results of the various update queries as returned by dbDelta.
1006 */
1007 public static function create_tables() {
1008 global $wpdb;
1009
1010 $wpdb->hide_errors();
1011
1012 require_once ABSPATH . 'wp-admin/includes/upgrade.php';
1013
1014 /**
1015 * Before updating with DBDELTA, remove any primary keys which could be
1016 * modified due to schema updates.
1017 */
1018 if ( $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->prefix}woocommerce_downloadable_product_permissions';" ) ) {
1019 if ( ! $wpdb->get_var( "SHOW COLUMNS FROM `{$wpdb->prefix}woocommerce_downloadable_product_permissions` LIKE 'permission_id';" ) ) {
1020 $wpdb->query( "ALTER TABLE {$wpdb->prefix}woocommerce_downloadable_product_permissions DROP PRIMARY KEY, ADD `permission_id` bigint(20) unsigned NOT NULL PRIMARY KEY AUTO_INCREMENT;" );
1021 }
1022 }
1023
1024 /**
1025 * Change wp_woocommerce_sessions schema to use a bigint auto increment field instead of char(32) field as
1026 * the primary key as it is not a good practice to use a char(32) field as the primary key of a table and as
1027 * there were reports of issues with this table (see https://github.com/woocommerce/woocommerce/issues/20912).
1028 *
1029 * This query needs to run before dbDelta() as this WP function is not able to handle primary key changes
1030 * (see https://github.com/woocommerce/woocommerce/issues/21534 and https://core.trac.wordpress.org/ticket/40357).
1031 */
1032 if ( $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->prefix}woocommerce_sessions'" ) ) {
1033 if ( ! $wpdb->get_var( "SHOW KEYS FROM {$wpdb->prefix}woocommerce_sessions WHERE Key_name = 'PRIMARY' AND Column_name = 'session_id'" ) ) {
1034 $wpdb->query(
1035 "ALTER TABLE `{$wpdb->prefix}woocommerce_sessions` DROP PRIMARY KEY, DROP KEY `session_id`, ADD PRIMARY KEY(`session_id`), ADD UNIQUE KEY(`session_key`)"
1036 );
1037 }
1038 }
1039
1040 $db_delta_result = dbDelta( self::get_schema() );
1041
1042 $index_exists = $wpdb->get_row( "SHOW INDEX FROM {$wpdb->comments} WHERE column_name = 'comment_type' and key_name = 'woo_idx_comment_type'" );
1043
1044 if ( is_null( $index_exists ) ) {
1045 // Add an index to the field comment_type to improve the response time of the query
1046 // used by WC_Comments::wp_count_comments() to get the number of comments by type.
1047 $wpdb->query( "ALTER TABLE {$wpdb->comments} ADD INDEX woo_idx_comment_type (comment_type)" );
1048 }
1049
1050 // Clear table caches.
1051 delete_transient( 'wc_attribute_taxonomies' );
1052
1053 return $db_delta_result;
1054 }
1055
1056 /**
1057 * Get Table schema.
1058 *
1059 * See https://github.com/woocommerce/woocommerce/wiki/Database-Description/
1060 *
1061 * A note on indexes; Indexes have a maximum size of 767 bytes. Historically, we haven't need to be concerned about that.
1062 * As of WordPress 4.2, however, we moved to utf8mb4, which uses 4 bytes per character. This means that an index which
1063 * used to have room for floor(767/3) = 255 characters, now only has room for floor(767/4) = 191 characters.
1064 *
1065 * Changing indexes may cause duplicate index notices in logs due to https://core.trac.wordpress.org/ticket/34870 but dropping
1066 * indexes first causes too much load on some servers/larger DB.
1067 *
1068 * When adding or removing a table, make sure to update the list of tables in WC_Install::get_tables().
1069 *
1070 * @return string
1071 */
1072 private static function get_schema() {
1073 global $wpdb;
1074
1075 $collate = '';
1076
1077 if ( $wpdb->has_cap( 'collation' ) ) {
1078 $collate = $wpdb->get_charset_collate();
1079 }
1080
1081 /*
1082 * Indexes have a maximum size of 767 bytes. Historically, we haven't need to be concerned about that.
1083 * As of WP 4.2, however, they moved to utf8mb4, which uses 4 bytes per character. This means that an index which
1084 * used to have room for floor(767/3) = 255 characters, now only has room for floor(767/4) = 191 characters.
1085 */
1086 $max_index_length = 191;
1087
1088 $product_attributes_lookup_table_creation_sql = wc_get_container()->get( DataRegenerator::class )->get_table_creation_sql();
1089
1090 $tables = "
1091 CREATE TABLE {$wpdb->prefix}woocommerce_sessions (
1092 session_id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
1093 session_key char(32) NOT NULL,
1094 session_value longtext NOT NULL,
1095 session_expiry bigint(20) unsigned NOT NULL,
1096 PRIMARY KEY (session_id),
1097 UNIQUE KEY session_key (session_key)
1098 ) $collate;
1099 CREATE TABLE {$wpdb->prefix}woocommerce_api_keys (
1100 key_id bigint(20) unsigned NOT NULL auto_increment,
1101 user_id bigint(20) unsigned NOT NULL,
1102 description varchar(200) NULL,
1103 permissions varchar(10) NOT NULL,
1104 consumer_key char(64) NOT NULL,
1105 consumer_secret char(43) NOT NULL,
1106 nonces longtext NULL,
1107 truncated_key char(7) NOT NULL,
1108 last_access datetime NULL default null,
1109 PRIMARY KEY (key_id),
1110 KEY consumer_key (consumer_key),
1111 KEY consumer_secret (consumer_secret)
1112 ) $collate;
1113 CREATE TABLE {$wpdb->prefix}woocommerce_attribute_taxonomies (
1114 attribute_id bigint(20) unsigned NOT NULL auto_increment,
1115 attribute_name varchar(200) NOT NULL,
1116 attribute_label varchar(200) NULL,
1117 attribute_type varchar(20) NOT NULL,
1118 attribute_orderby varchar(20) NOT NULL,
1119 attribute_public int(1) NOT NULL DEFAULT 1,
1120 PRIMARY KEY (attribute_id),
1121 KEY attribute_name (attribute_name(20))
1122 ) $collate;
1123 CREATE TABLE {$wpdb->prefix}woocommerce_downloadable_product_permissions (
1124 permission_id bigint(20) unsigned NOT NULL auto_increment,
1125 download_id varchar(36) NOT NULL,
1126 product_id bigint(20) unsigned NOT NULL,
1127 order_id bigint(20) unsigned NOT NULL DEFAULT 0,
1128 order_key varchar(200) NOT NULL,
1129 user_email varchar(200) NOT NULL,
1130 user_id bigint(20) unsigned NULL,
1131 downloads_remaining varchar(9) NULL,
1132 access_granted datetime NOT NULL default '0000-00-00 00:00:00',
1133 access_expires datetime NULL default null,
1134 download_count bigint(20) unsigned NOT NULL DEFAULT 0,
1135 PRIMARY KEY (permission_id),
1136 KEY download_order_key_product (product_id,order_id,order_key(16),download_id),
1137 KEY download_order_product (download_id,order_id,product_id),
1138 KEY order_id (order_id),
1139 KEY user_order_remaining_expires (user_id,order_id,downloads_remaining,access_expires)
1140 ) $collate;
1141 CREATE TABLE {$wpdb->prefix}woocommerce_order_items (
1142 order_item_id bigint(20) unsigned NOT NULL auto_increment,
1143 order_item_name text NOT NULL,
1144 order_item_type varchar(200) NOT NULL DEFAULT '',
1145 order_id bigint(20) unsigned NOT NULL,
1146 PRIMARY KEY (order_item_id),
1147 KEY order_id (order_id)
1148 ) $collate;
1149 CREATE TABLE {$wpdb->prefix}woocommerce_order_itemmeta (
1150 meta_id bigint(20) unsigned NOT NULL auto_increment,
1151 order_item_id bigint(20) unsigned NOT NULL,
1152 meta_key varchar(255) default NULL,
1153 meta_value longtext NULL,
1154 PRIMARY KEY (meta_id),
1155 KEY order_item_id (order_item_id),
1156 KEY meta_key (meta_key(32))
1157 ) $collate;
1158 CREATE TABLE {$wpdb->prefix}woocommerce_tax_rates (
1159 tax_rate_id bigint(20) unsigned NOT NULL auto_increment,
1160 tax_rate_country varchar(2) NOT NULL DEFAULT '',
1161 tax_rate_state varchar(200) NOT NULL DEFAULT '',
1162 tax_rate varchar(8) NOT NULL DEFAULT '',
1163 tax_rate_name varchar(200) NOT NULL DEFAULT '',
1164 tax_rate_priority bigint(20) unsigned NOT NULL,
1165 tax_rate_compound int(1) NOT NULL DEFAULT 0,
1166 tax_rate_shipping int(1) NOT NULL DEFAULT 1,
1167 tax_rate_order bigint(20) unsigned NOT NULL,
1168 tax_rate_class varchar(200) NOT NULL DEFAULT '',
1169 PRIMARY KEY (tax_rate_id),
1170 KEY tax_rate_country (tax_rate_country),
1171 KEY tax_rate_state (tax_rate_state(2)),
1172 KEY tax_rate_class (tax_rate_class(10)),
1173 KEY tax_rate_priority (tax_rate_priority)
1174 ) $collate;
1175 CREATE TABLE {$wpdb->prefix}woocommerce_tax_rate_locations (
1176 location_id bigint(20) unsigned NOT NULL auto_increment,
1177 location_code varchar(200) NOT NULL,
1178 tax_rate_id bigint(20) unsigned NOT NULL,
1179 location_type varchar(40) NOT NULL,
1180 PRIMARY KEY (location_id),
1181 KEY tax_rate_id (tax_rate_id),
1182 KEY location_type_code (location_type(10),location_code(20))
1183 ) $collate;
1184 CREATE TABLE {$wpdb->prefix}woocommerce_shipping_zones (
1185 zone_id bigint(20) unsigned NOT NULL auto_increment,
1186 zone_name varchar(200) NOT NULL,
1187 zone_order bigint(20) unsigned NOT NULL,
1188 PRIMARY KEY (zone_id)
1189 ) $collate;
1190 CREATE TABLE {$wpdb->prefix}woocommerce_shipping_zone_locations (
1191 location_id bigint(20) unsigned NOT NULL auto_increment,
1192 zone_id bigint(20) unsigned NOT NULL,
1193 location_code varchar(200) NOT NULL,
1194 location_type varchar(40) NOT NULL,
1195 PRIMARY KEY (location_id),
1196 KEY location_id (location_id),
1197 KEY location_type_code (location_type(10),location_code(20))
1198 ) $collate;
1199 CREATE TABLE {$wpdb->prefix}woocommerce_shipping_zone_methods (
1200 zone_id bigint(20) unsigned NOT NULL,
1201 instance_id bigint(20) unsigned NOT NULL auto_increment,
1202 method_id varchar(200) NOT NULL,
1203 method_order bigint(20) unsigned NOT NULL,
1204 is_enabled tinyint(1) NOT NULL DEFAULT '1',
1205 PRIMARY KEY (instance_id)
1206 ) $collate;
1207 CREATE TABLE {$wpdb->prefix}woocommerce_payment_tokens (
1208 token_id bigint(20) unsigned NOT NULL auto_increment,
1209 gateway_id varchar(200) NOT NULL,
1210 token text NOT NULL,
1211 user_id bigint(20) unsigned NOT NULL DEFAULT '0',
1212 type varchar(200) NOT NULL,
1213 is_default tinyint(1) NOT NULL DEFAULT '0',
1214 PRIMARY KEY (token_id),
1215 KEY user_id (user_id)
1216 ) $collate;
1217 CREATE TABLE {$wpdb->prefix}woocommerce_payment_tokenmeta (
1218 meta_id bigint(20) unsigned NOT NULL auto_increment,
1219 payment_token_id bigint(20) unsigned NOT NULL,
1220 meta_key varchar(255) NULL,
1221 meta_value longtext NULL,
1222 PRIMARY KEY (meta_id),
1223 KEY payment_token_id (payment_token_id),
1224 KEY meta_key (meta_key(32))
1225 ) $collate;
1226 CREATE TABLE {$wpdb->prefix}woocommerce_log (
1227 log_id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
1228 timestamp datetime NOT NULL,
1229 level smallint(4) NOT NULL,
1230 source varchar(200) NOT NULL,
1231 message longtext NOT NULL,
1232 context longtext NULL,
1233 PRIMARY KEY (log_id),
1234 KEY level (level)
1235 ) $collate;
1236 CREATE TABLE {$wpdb->prefix}wc_webhooks (
1237 webhook_id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
1238 status varchar(200) NOT NULL,
1239 name text NOT NULL,
1240 user_id bigint(20) unsigned NOT NULL,
1241 delivery_url text NOT NULL,
1242 secret text NOT NULL,
1243 topic varchar(200) NOT NULL,
1244 date_created datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
1245 date_created_gmt datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
1246 date_modified datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
1247 date_modified_gmt datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
1248 api_version smallint(4) NOT NULL,
1249 failure_count smallint(10) NOT NULL DEFAULT '0',
1250 pending_delivery tinyint(1) NOT NULL DEFAULT '0',
1251 PRIMARY KEY (webhook_id),
1252 KEY user_id (user_id)
1253 ) $collate;
1254 CREATE TABLE {$wpdb->prefix}wc_download_log (
1255 download_log_id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
1256 timestamp datetime NOT NULL,
1257 permission_id bigint(20) unsigned NOT NULL,
1258 user_id bigint(20) unsigned NULL,
1259 user_ip_address varchar(100) NULL DEFAULT '',
1260 PRIMARY KEY (download_log_id),
1261 KEY permission_id (permission_id),
1262 KEY timestamp (timestamp)
1263 ) $collate;
1264 CREATE TABLE {$wpdb->prefix}wc_product_meta_lookup (
1265 `product_id` bigint(20) NOT NULL,
1266 `sku` varchar(100) NULL default '',
1267 `virtual` tinyint(1) NULL default 0,
1268 `downloadable` tinyint(1) NULL default 0,
1269 `min_price` decimal(19,4) NULL default NULL,
1270 `max_price` decimal(19,4) NULL default NULL,
1271 `onsale` tinyint(1) NULL default 0,
1272 `stock_quantity` double NULL default NULL,
1273 `stock_status` varchar(100) NULL default 'instock',
1274 `rating_count` bigint(20) NULL default 0,
1275 `average_rating` decimal(3,2) NULL default 0.00,
1276 `total_sales` bigint(20) NULL default 0,
1277 `tax_status` varchar(100) NULL default 'taxable',
1278 `tax_class` varchar(100) NULL default '',
1279 PRIMARY KEY (`product_id`),
1280 KEY `virtual` (`virtual`),
1281 KEY `downloadable` (`downloadable`),
1282 KEY `stock_status` (`stock_status`),
1283 KEY `stock_quantity` (`stock_quantity`),
1284 KEY `onsale` (`onsale`),
1285 KEY min_max_price (`min_price`, `max_price`)
1286 ) $collate;
1287 CREATE TABLE {$wpdb->prefix}wc_tax_rate_classes (
1288 tax_rate_class_id bigint(20) unsigned NOT NULL auto_increment,
1289 name varchar(200) NOT NULL DEFAULT '',
1290 slug varchar(200) NOT NULL DEFAULT '',
1291 PRIMARY KEY (tax_rate_class_id),
1292 UNIQUE KEY slug (slug($max_index_length))
1293 ) $collate;
1294 CREATE TABLE {$wpdb->prefix}wc_reserved_stock (
1295 `order_id` bigint(20) NOT NULL,
1296 `product_id` bigint(20) NOT NULL,
1297 `stock_quantity` double NOT NULL DEFAULT 0,
1298 `timestamp` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
1299 `expires` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
1300 PRIMARY KEY (`order_id`, `product_id`)
1301 ) $collate;
1302 CREATE TABLE {$wpdb->prefix}wc_rate_limits (
1303 rate_limit_id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
1304 rate_limit_key varchar(200) NOT NULL,
1305 rate_limit_expiry bigint(20) unsigned NOT NULL,
1306 rate_limit_remaining smallint(10) NOT NULL DEFAULT '0',
1307 PRIMARY KEY (rate_limit_id),
1308 UNIQUE KEY rate_limit_key (rate_limit_key($max_index_length))
1309 ) $collate;
1310 $product_attributes_lookup_table_creation_sql
1311 CREATE TABLE {$wpdb->prefix}wc_product_download_directories (
1312 url_id bigint(20) unsigned NOT NULL auto_increment,
1313 url varchar(256) NOT NULL,
1314 enabled tinyint(1) NOT NULL DEFAULT 0,
1315 PRIMARY KEY (url_id),
1316 KEY url (url($max_index_length))
1317 ) $collate;
1318 CREATE TABLE {$wpdb->prefix}wc_order_stats (
1319 order_id bigint(20) unsigned NOT NULL,
1320 parent_id bigint(20) unsigned DEFAULT 0 NOT NULL,
1321 date_created datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
1322 date_created_gmt datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
1323 date_paid datetime DEFAULT '0000-00-00 00:00:00',
1324 date_completed datetime DEFAULT '0000-00-00 00:00:00',
1325 num_items_sold int(11) DEFAULT 0 NOT NULL,
1326 total_sales double DEFAULT 0 NOT NULL,
1327 tax_total double DEFAULT 0 NOT NULL,
1328 shipping_total double DEFAULT 0 NOT NULL,
1329 net_total double DEFAULT 0 NOT NULL,
1330 returning_customer tinyint(1) DEFAULT NULL,
1331 status varchar(200) NOT NULL,
1332 customer_id bigint(20) unsigned NOT NULL,
1333 PRIMARY KEY (order_id),
1334 KEY date_created (date_created),
1335 KEY customer_id (customer_id),
1336 KEY status (status({$max_index_length}))
1337 ) $collate;
1338 CREATE TABLE {$wpdb->prefix}wc_order_product_lookup (
1339 order_item_id bigint(20) unsigned NOT NULL,
1340 order_id bigint(20) unsigned NOT NULL,
1341 product_id bigint(20) unsigned NOT NULL,
1342 variation_id bigint(20) unsigned NOT NULL,
1343 customer_id bigint(20) unsigned NULL,
1344 date_created datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
1345 product_qty int(11) NOT NULL,
1346 product_net_revenue double DEFAULT 0 NOT NULL,
1347 product_gross_revenue double DEFAULT 0 NOT NULL,
1348 coupon_amount double DEFAULT 0 NOT NULL,
1349 tax_amount double DEFAULT 0 NOT NULL,
1350 shipping_amount double DEFAULT 0 NOT NULL,
1351 shipping_tax_amount double DEFAULT 0 NOT NULL,
1352 PRIMARY KEY (order_item_id),
1353 KEY order_id (order_id),
1354 KEY product_id (product_id),
1355 KEY customer_id (customer_id),
1356 KEY date_created (date_created)
1357 ) $collate;
1358 CREATE TABLE {$wpdb->prefix}wc_order_tax_lookup (
1359 order_id bigint(20) unsigned NOT NULL,
1360 tax_rate_id bigint(20) unsigned NOT NULL,
1361 date_created datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
1362 shipping_tax double DEFAULT 0 NOT NULL,
1363 order_tax double DEFAULT 0 NOT NULL,
1364 total_tax double DEFAULT 0 NOT NULL,
1365 PRIMARY KEY (order_id, tax_rate_id),
1366 KEY tax_rate_id (tax_rate_id),
1367 KEY date_created (date_created)
1368 ) $collate;
1369 CREATE TABLE {$wpdb->prefix}wc_order_coupon_lookup (
1370 order_id bigint(20) unsigned NOT NULL,
1371 coupon_id bigint(20) NOT NULL,
1372 date_created datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
1373 discount_amount double DEFAULT 0 NOT NULL,
1374 PRIMARY KEY (order_id, coupon_id),
1375 KEY coupon_id (coupon_id),
1376 KEY date_created (date_created)
1377 ) $collate;
1378 CREATE TABLE {$wpdb->prefix}wc_admin_notes (
1379 note_id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
1380 name varchar(255) NOT NULL,
1381 type varchar(20) NOT NULL,
1382 locale varchar(20) NOT NULL,
1383 title longtext NOT NULL,
1384 content longtext NOT NULL,
1385 content_data longtext NULL default null,
1386 status varchar(200) NOT NULL,
1387 source varchar(200) NOT NULL,
1388 date_created datetime NOT NULL default '0000-00-00 00:00:00',
1389 date_reminder datetime NULL default null,
1390 is_snoozable tinyint(1) DEFAULT 0 NOT NULL,
1391 layout varchar(20) DEFAULT '' NOT NULL,
1392 image varchar(200) NULL DEFAULT NULL,
1393 is_deleted tinyint(1) DEFAULT 0 NOT NULL,
1394 is_read tinyint(1) DEFAULT 0 NOT NULL,
1395 icon varchar(200) NOT NULL default 'info',
1396 PRIMARY KEY (note_id)
1397 ) $collate;
1398 CREATE TABLE {$wpdb->prefix}wc_admin_note_actions (
1399 action_id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
1400 note_id bigint(20) unsigned NOT NULL,
1401 name varchar(255) NOT NULL,
1402 label varchar(255) NOT NULL,
1403 query longtext NOT NULL,
1404 status varchar(255) NOT NULL,
1405 actioned_text varchar(255) NOT NULL,
1406 nonce_action varchar(255) NULL DEFAULT NULL,
1407 nonce_name varchar(255) NULL DEFAULT NULL,
1408 PRIMARY KEY (action_id),
1409 KEY note_id (note_id)
1410 ) $collate;
1411 CREATE TABLE {$wpdb->prefix}wc_customer_lookup (
1412 customer_id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
1413 user_id bigint(20) unsigned DEFAULT NULL,
1414 username varchar(60) DEFAULT '' NOT NULL,
1415 first_name varchar(255) NOT NULL,
1416 last_name varchar(255) NOT NULL,
1417 email varchar(100) NULL default NULL,
1418 date_last_active timestamp NULL default null,
1419 date_registered timestamp NULL default null,
1420 country char(2) DEFAULT '' NOT NULL,
1421 postcode varchar(20) DEFAULT '' NOT NULL,
1422 city varchar(100) DEFAULT '' NOT NULL,
1423 state varchar(100) DEFAULT '' NOT NULL,
1424 PRIMARY KEY (customer_id),
1425 UNIQUE KEY user_id (user_id),
1426 KEY email (email)
1427 ) $collate;
1428 CREATE TABLE {$wpdb->prefix}wc_category_lookup (
1429 category_tree_id bigint(20) unsigned NOT NULL,
1430 category_id bigint(20) unsigned NOT NULL,
1431 PRIMARY KEY (category_tree_id,category_id)
1432 ) $collate;
1433 ";
1434
1435 return $tables;
1436 }
1437
1438 /**
1439 * Return a list of WooCommerce tables. Used to make sure all WC tables are dropped when uninstalling the plugin
1440 * in a single site or multi site environment.
1441 *
1442 * @return array WC tables.
1443 */
1444 public static function get_tables() {
1445 global $wpdb;
1446
1447 $tables = array(
1448 "{$wpdb->prefix}wc_download_log",
1449 "{$wpdb->prefix}wc_product_download_directories",
1450 "{$wpdb->prefix}wc_product_meta_lookup",
1451 "{$wpdb->prefix}wc_tax_rate_classes",
1452 "{$wpdb->prefix}wc_webhooks",
1453 "{$wpdb->prefix}woocommerce_api_keys",
1454 "{$wpdb->prefix}woocommerce_attribute_taxonomies",
1455 "{$wpdb->prefix}woocommerce_downloadable_product_permissions",
1456 "{$wpdb->prefix}woocommerce_log",
1457 "{$wpdb->prefix}woocommerce_order_itemmeta",
1458 "{$wpdb->prefix}woocommerce_order_items",
1459 "{$wpdb->prefix}woocommerce_payment_tokenmeta",
1460 "{$wpdb->prefix}woocommerce_payment_tokens",
1461 "{$wpdb->prefix}woocommerce_sessions",
1462 "{$wpdb->prefix}woocommerce_shipping_zone_locations",
1463 "{$wpdb->prefix}woocommerce_shipping_zone_methods",
1464 "{$wpdb->prefix}woocommerce_shipping_zones",
1465 "{$wpdb->prefix}woocommerce_tax_rate_locations",
1466 "{$wpdb->prefix}woocommerce_tax_rates",
1467 "{$wpdb->prefix}wc_reserved_stock",
1468 "{$wpdb->prefix}wc_rate_limits",
1469 wc_get_container()->get( DataRegenerator::class )->get_lookup_table_name(),
1470
1471 // WCA Tables.
1472 "{$wpdb->prefix}wc_order_stats",
1473 "{$wpdb->prefix}wc_order_product_lookup",
1474 "{$wpdb->prefix}wc_order_tax_lookup",
1475 "{$wpdb->prefix}wc_order_coupon_lookup",
1476 "{$wpdb->prefix}wc_admin_notes",
1477 "{$wpdb->prefix}wc_admin_note_actions",
1478 "{$wpdb->prefix}wc_customer_lookup",
1479 "{$wpdb->prefix}wc_category_lookup",
1480 );
1481
1482 /**
1483 * Filter the list of known WooCommerce tables.
1484 *
1485 * If WooCommerce plugins need to add new tables, they can inject them here.
1486 *
1487 * @param array $tables An array of WooCommerce-specific database table names.
1488 * @since 3.4.0
1489 */
1490 $tables = apply_filters( 'woocommerce_install_get_tables', $tables );
1491
1492 return $tables;
1493 }
1494
1495 /**
1496 * Drop WooCommerce tables.
1497 *
1498 * @return void
1499 */
1500 public static function drop_tables() {
1501 global $wpdb;
1502
1503 $tables = self::get_tables();
1504
1505 foreach ( $tables as $table ) {
1506 $wpdb->query( "DROP TABLE IF EXISTS {$table}" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
1507 }
1508 }
1509
1510 /**
1511 * Uninstall tables when MU blog is deleted.
1512 *
1513 * @param array $tables List of tables that will be deleted by WP.
1514 *
1515 * @return string[]
1516 */
1517 public static function wpmu_drop_tables( $tables ) {
1518 return array_merge( $tables, self::get_tables() );
1519 }
1520
1521 /**
1522 * Create roles and capabilities.
1523 */
1524 public static function create_roles() {
1525 global $wp_roles;
1526
1527 if ( ! class_exists( 'WP_Roles' ) ) {
1528 return;
1529 }
1530
1531 if ( ! isset( $wp_roles ) ) {
1532 $wp_roles = new WP_Roles(); // @codingStandardsIgnoreLine
1533 }
1534
1535 // Dummy gettext calls to get strings in the catalog.
1536 /* translators: user role */
1537 _x( 'Customer', 'User role', 'woocommerce' );
1538 /* translators: user role */
1539 _x( 'Shop manager', 'User role', 'woocommerce' );
1540
1541 // Customer role.
1542 add_role(
1543 'customer',
1544 'Customer',
1545 array(
1546 'read' => true,
1547 )
1548 );
1549
1550 // Shop manager role.
1551 add_role(
1552 'shop_manager',
1553 'Shop manager',
1554 array(
1555 'level_9' => true,
1556 'level_8' => true,
1557 'level_7' => true,
1558 'level_6' => true,
1559 'level_5' => true,
1560 'level_4' => true,
1561 'level_3' => true,
1562 'level_2' => true,
1563 'level_1' => true,
1564 'level_0' => true,
1565 'read' => true,
1566 'read_private_pages' => true,
1567 'read_private_posts' => true,
1568 'edit_posts' => true,
1569 'edit_pages' => true,
1570 'edit_published_posts' => true,
1571 'edit_published_pages' => true,
1572 'edit_private_pages' => true,
1573 'edit_private_posts' => true,
1574 'edit_others_posts' => true,
1575 'edit_others_pages' => true,
1576 'publish_posts' => true,
1577 'publish_pages' => true,
1578 'delete_posts' => true,
1579 'delete_pages' => true,
1580 'delete_private_pages' => true,
1581 'delete_private_posts' => true,
1582 'delete_published_pages' => true,
1583 'delete_published_posts' => true,
1584 'delete_others_posts' => true,
1585 'delete_others_pages' => true,
1586 'manage_categories' => true,
1587 'manage_links' => true,
1588 'moderate_comments' => true,
1589 'upload_files' => true,
1590 'export' => true,
1591 'import' => true,
1592 'list_users' => true,
1593 'edit_theme_options' => true,
1594 )
1595 );
1596
1597 $capabilities = self::get_core_capabilities();
1598
1599 foreach ( $capabilities as $cap_group ) {
1600 foreach ( $cap_group as $cap ) {
1601 $wp_roles->add_cap( 'shop_manager', $cap );
1602 $wp_roles->add_cap( 'administrator', $cap );
1603 }
1604 }
1605 }
1606
1607 /**
1608 * Get capabilities for WooCommerce - these are assigned to admin/shop manager during installation or reset.
1609 *
1610 * @return array
1611 */
1612 public static function get_core_capabilities() {
1613 $capabilities = array();
1614
1615 $capabilities['core'] = array(
1616 'manage_woocommerce',
1617 'view_woocommerce_reports',
1618 );
1619
1620 $capability_types = array( 'product', 'shop_order', 'shop_coupon' );
1621
1622 foreach ( $capability_types as $capability_type ) {
1623
1624 $capabilities[ $capability_type ] = array(
1625 // Post type.
1626 "edit_{$capability_type}",
1627 "read_{$capability_type}",
1628 "delete_{$capability_type}",
1629 "edit_{$capability_type}s",
1630 "edit_others_{$capability_type}s",
1631 "publish_{$capability_type}s",
1632 "read_private_{$capability_type}s",
1633 "delete_{$capability_type}s",
1634 "delete_private_{$capability_type}s",
1635 "delete_published_{$capability_type}s",
1636 "delete_others_{$capability_type}s",
1637 "edit_private_{$capability_type}s",
1638 "edit_published_{$capability_type}s",
1639
1640 // Terms.
1641 "manage_{$capability_type}_terms",
1642 "edit_{$capability_type}_terms",
1643 "delete_{$capability_type}_terms",
1644 "assign_{$capability_type}_terms",
1645 );
1646 }
1647
1648 return $capabilities;
1649 }
1650
1651 /**
1652 * Remove WooCommerce roles.
1653 */
1654 public static function remove_roles() {
1655 global $wp_roles;
1656
1657 if ( ! class_exists( 'WP_Roles' ) ) {
1658 return;
1659 }
1660
1661 if ( ! isset( $wp_roles ) ) {
1662 $wp_roles = new WP_Roles(); // @codingStandardsIgnoreLine
1663 }
1664
1665 $capabilities = self::get_core_capabilities();
1666
1667 foreach ( $capabilities as $cap_group ) {
1668 foreach ( $cap_group as $cap ) {
1669 $wp_roles->remove_cap( 'shop_manager', $cap );
1670 $wp_roles->remove_cap( 'administrator', $cap );
1671 }
1672 }
1673
1674 remove_role( 'customer' );
1675 remove_role( 'shop_manager' );
1676 }
1677
1678 /**
1679 * Create files/directories.
1680 */
1681 private static function create_files() {
1682 /**
1683 * Bypass if filesystem is read-only and/or non-standard upload system is used.
1684 *
1685 * @since 3.2.0
1686 */
1687 if ( apply_filters( 'woocommerce_install_skip_create_files', false ) ) {
1688 return;
1689 }
1690
1691 // Install files and folders for uploading files and prevent hotlinking.
1692 $upload_dir = wp_get_upload_dir();
1693 $download_method = get_option( 'woocommerce_file_download_method', 'force' );
1694
1695 $files = array(
1696 array(
1697 'base' => $upload_dir['basedir'] . '/woocommerce_uploads',
1698 'file' => 'index.html',
1699 'content' => '',
1700 ),
1701 array(
1702 'base' => WC_LOG_DIR,
1703 'file' => '.htaccess',
1704 'content' => 'deny from all',
1705 ),
1706 array(
1707 'base' => WC_LOG_DIR,
1708 'file' => 'index.html',
1709 'content' => '',
1710 ),
1711 array(
1712 'base' => $upload_dir['basedir'] . '/woocommerce_uploads',
1713 'file' => '.htaccess',
1714 'content' => 'redirect' === $download_method ? 'Options -Indexes' : 'deny from all',
1715 ),
1716 );
1717
1718 foreach ( $files as $file ) {
1719 if ( wp_mkdir_p( $file['base'] ) && ! file_exists( trailingslashit( $file['base'] ) . $file['file'] ) ) {
1720 $file_handle = @fopen( trailingslashit( $file['base'] ) . $file['file'], 'wb' ); // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged, WordPress.WP.AlternativeFunctions.file_system_read_fopen
1721 if ( $file_handle ) {
1722 fwrite( $file_handle, $file['content'] ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fwrite
1723 fclose( $file_handle ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_read_fclose
1724 }
1725 }
1726 }
1727
1728 // Create attachment for placeholders.
1729 self::create_placeholder_image();
1730 }
1731
1732 /**
1733 * Create a placeholder image in the media library.
1734 *
1735 * @since 3.5.0
1736 */
1737 private static function create_placeholder_image() {
1738 $placeholder_image = get_option( 'woocommerce_placeholder_image', 0 );
1739
1740 // Validate current setting if set. If set, return.
1741 if ( ! empty( $placeholder_image ) ) {
1742 if ( ! is_numeric( $placeholder_image ) ) {
1743 return;
1744 } elseif ( $placeholder_image && wp_attachment_is_image( $placeholder_image ) ) {
1745 return;
1746 }
1747 }
1748
1749 $upload_dir = wp_upload_dir();
1750 $source = WC()->plugin_path() . '/assets/images/placeholder-attachment.png';
1751 $filename = $upload_dir['basedir'] . '/woocommerce-placeholder.png';
1752
1753 if ( ! file_exists( $filename ) ) {
1754 copy( $source, $filename ); // @codingStandardsIgnoreLine.
1755 }
1756
1757 if ( ! file_exists( $filename ) ) {
1758 update_option( 'woocommerce_placeholder_image', 0 );
1759 return;
1760 }
1761
1762 $filetype = wp_check_filetype( basename( $filename ), null );
1763 $attachment = array(
1764 'guid' => $upload_dir['url'] . '/' . basename( $filename ),
1765 'post_mime_type' => $filetype['type'],
1766 'post_title' => preg_replace( '/\.[^.]+$/', '', basename( $filename ) ),
1767 'post_content' => '',
1768 'post_status' => 'inherit',
1769 );
1770
1771 $attach_id = wp_insert_attachment( $attachment, $filename );
1772 if ( is_wp_error( $attach_id ) ) {
1773 update_option( 'woocommerce_placeholder_image', 0 );
1774 return;
1775 }
1776
1777 update_option( 'woocommerce_placeholder_image', $attach_id );
1778
1779 // Make sure that this file is included, as wp_generate_attachment_metadata() depends on it.
1780 require_once ABSPATH . 'wp-admin/includes/image.php';
1781
1782 // Generate the metadata for the attachment, and update the database record.
1783 $attach_data = wp_generate_attachment_metadata( $attach_id, $filename );
1784 wp_update_attachment_metadata( $attach_id, $attach_data );
1785 }
1786
1787 /**
1788 * Show action links on the plugin screen.
1789 *
1790 * @param mixed $links Plugin Action links.
1791 *
1792 * @return array
1793 */
1794 public static function plugin_action_links( $links ) {
1795 $action_links = array(
1796 'settings' => '<a href="' . admin_url( 'admin.php?page=wc-settings' ) . '" aria-label="' . esc_attr__( 'View WooCommerce settings', 'woocommerce' ) . '">' . esc_html__( 'Settings', 'woocommerce' ) . '</a>',
1797 );
1798
1799 return array_merge( $action_links, $links );
1800 }
1801
1802 /**
1803 * Show row meta on the plugin screen.
1804 *
1805 * @param mixed $links Plugin Row Meta.
1806 * @param mixed $file Plugin Base file.
1807 *
1808 * @return array
1809 */
1810 public static function plugin_row_meta( $links, $file ) {
1811 if ( WC_PLUGIN_BASENAME !== $file ) {
1812 return $links;
1813 }
1814
1815 /**
1816 * The WooCommerce documentation URL.
1817 *
1818 * @since 2.7.0
1819 */
1820 $docs_url = apply_filters( 'woocommerce_docs_url', 'https://docs.woocommerce.com/documentation/plugins/woocommerce/' );
1821
1822 /**
1823 * The WooCommerce API documentation URL.
1824 *
1825 * @since 2.2.0
1826 */
1827 $api_docs_url = apply_filters( 'woocommerce_apidocs_url', 'https://docs.woocommerce.com/wc-apidocs/' );
1828
1829 /**
1830 * The community WooCommerce support URL.
1831 *
1832 * @since 2.2.0
1833 */
1834 $community_support_url = apply_filters( 'woocommerce_community_support_url', 'https://wordpress.org/support/plugin/woocommerce/' );
1835
1836 /**
1837 * The premium support URL.
1838 *
1839 * @since
1840 */
1841 $support_url = apply_filters( 'woocommerce_support_url', 'https://woocommerce.com/my-account/create-a-ticket/' );
1842
1843 $row_meta = array(
1844 'docs' => '<a href="' . esc_url( $docs_url ) . '" aria-label="' . esc_attr__( 'View WooCommerce documentation', 'woocommerce' ) . '">' . esc_html__( 'Docs', 'woocommerce' ) . '</a>',
1845 'apidocs' => '<a href="' . esc_url( $api_docs_url ) . '" aria-label="' . esc_attr__( 'View WooCommerce API docs', 'woocommerce' ) . '">' . esc_html__( 'API docs', 'woocommerce' ) . '</a>',
1846 'support' => '<a href="' . esc_url( $community_support_url ) . '" aria-label="' . esc_attr__( 'Visit community forums', 'woocommerce' ) . '">' . esc_html__( 'Community support', 'woocommerce' ) . '</a>',
1847 );
1848
1849 if ( WCConnectionHelper::is_connected() ) {
1850 $row_meta['premium_support'] = '<a href="' . esc_url( $support_url ) . '" aria-label="' . esc_attr__( 'Visit premium customer support', 'woocommerce' ) . '">' . esc_html__( 'Premium support', 'woocommerce' ) . '</a>';
1851 }
1852
1853 return array_merge( $links, $row_meta );
1854 }
1855
1856 /**
1857 * Get slug from path and associate it with the path.
1858 *
1859 * @param array $plugins Associative array of plugin files to paths.
1860 * @param string $key Plugin relative path. Example: woocommerce/woocommerce.php.
1861 */
1862 private static function associate_plugin_file( $plugins, $key ) {
1863 $path = explode( '/', $key );
1864 $filename = end( $path );
1865 $plugins[ $filename ] = $key;
1866 return $plugins;
1867 }
1868
1869 /**
1870 * Install a plugin from .org in the background via a cron job (used by
1871 * installer - opt in).
1872 *
1873 * @param string $plugin_to_install_id Plugin ID.
1874 * @param array $plugin_to_install Plugin information.
1875 *
1876 * @throws Exception If unable to proceed with plugin installation.
1877 * @since 2.6.0
1878 */
1879 public static function background_installer( $plugin_to_install_id, $plugin_to_install ) {
1880 // Explicitly clear the event.
1881 $args = func_get_args();
1882
1883 if ( ! empty( $plugin_to_install['repo-slug'] ) ) {
1884 require_once ABSPATH . 'wp-admin/includes/file.php';
1885 require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
1886 require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
1887 require_once ABSPATH . 'wp-admin/includes/plugin.php';
1888
1889 WP_Filesystem();
1890
1891 $skin = new Automatic_Upgrader_Skin();
1892 $upgrader = new WP_Upgrader( $skin );
1893 $installed_plugins = array_reduce( array_keys( get_plugins() ), array( __CLASS__, 'associate_plugin_file' ) );
1894 if ( empty( $installed_plugins ) ) {
1895 $installed_plugins = array();
1896 }
1897 $plugin_slug = $plugin_to_install['repo-slug'];
1898 $plugin_file = isset( $plugin_to_install['file'] ) ? $plugin_to_install['file'] : $plugin_slug . '.php';
1899 $installed = false;
1900 $activate = false;
1901
1902 // See if the plugin is installed already.
1903 if ( isset( $installed_plugins[ $plugin_file ] ) ) {
1904 $installed = true;
1905 $activate = ! is_plugin_active( $installed_plugins[ $plugin_file ] );
1906 }
1907
1908 // Install this thing!
1909 if ( ! $installed ) {
1910 // Suppress feedback.
1911 ob_start();
1912
1913 try {
1914 $plugin_information = plugins_api(
1915 'plugin_information',
1916 array(
1917 'slug' => $plugin_slug,
1918 'fields' => array(
1919 'short_description' => false,
1920 'sections' => false,
1921 'requires' => false,
1922 'rating' => false,
1923 'ratings' => false,
1924 'downloaded' => false,
1925 'last_updated' => false,
1926 'added' => false,
1927 'tags' => false,
1928 'homepage' => false,
1929 'donate_link' => false,
1930 'author_profile' => false,
1931 'author' => false,
1932 ),
1933 )
1934 );
1935
1936 if ( is_wp_error( $plugin_information ) ) {
1937 throw new Exception( $plugin_information->get_error_message() );
1938 }
1939
1940 $package = $plugin_information->download_link;
1941 $download = $upgrader->download_package( $package );
1942
1943 if ( is_wp_error( $download ) ) {
1944 throw new Exception( $download->get_error_message() );
1945 }
1946
1947 $working_dir = $upgrader->unpack_package( $download, true );
1948
1949 if ( is_wp_error( $working_dir ) ) {
1950 throw new Exception( $working_dir->get_error_message() );
1951 }
1952
1953 $result = $upgrader->install_package(
1954 array(
1955 'source' => $working_dir,
1956 'destination' => WP_PLUGIN_DIR,
1957 'clear_destination' => false,
1958 'abort_if_destination_exists' => false,
1959 'clear_working' => true,
1960 'hook_extra' => array(
1961 'type' => 'plugin',
1962 'action' => 'install',
1963 ),
1964 )
1965 );
1966
1967 if ( is_wp_error( $result ) ) {
1968 throw new Exception( $result->get_error_message() );
1969 }
1970
1971 $activate = true;
1972
1973 } catch ( Exception $e ) {
1974 WC_Admin_Notices::add_custom_notice(
1975 $plugin_to_install_id . '_install_error',
1976 sprintf(
1977 // translators: 1: plugin name, 2: error message, 3: URL to install plugin manually.
1978 __( '%1$s could not be installed (%2$s). <a href="%3$s">Please install it manually by clicking here.</a>', 'woocommerce' ),
1979 $plugin_to_install['name'],
1980 $e->getMessage(),
1981 esc_url( admin_url( 'index.php?wc-install-plugin-redirect=' . $plugin_slug ) )
1982 )
1983 );
1984 }
1985
1986 // Discard feedback.
1987 ob_end_clean();
1988 }
1989
1990 wp_clean_plugins_cache();
1991
1992 // Activate this thing.
1993 if ( $activate ) {
1994 try {
1995 add_action( 'add_option_mailchimp_woocommerce_plugin_do_activation_redirect', array( __CLASS__, 'remove_mailchimps_redirect' ), 10, 2 );
1996 $result = activate_plugin( $installed ? $installed_plugins[ $plugin_file ] : $plugin_slug . '/' . $plugin_file );
1997
1998 if ( is_wp_error( $result ) ) {
1999 throw new Exception( $result->get_error_message() );
2000 }
2001 } catch ( Exception $e ) {
2002 WC_Admin_Notices::add_custom_notice(
2003 $plugin_to_install_id . '_install_error',
2004 sprintf(
2005 // translators: 1: plugin name, 2: URL to WP plugin page.
2006 __( '%1$s was installed but could not be activated. <a href="%2$s">Please activate it manually by clicking here.</a>', 'woocommerce' ),
2007 $plugin_to_install['name'],
2008 admin_url( 'plugins.php' )
2009 )
2010 );
2011 }
2012 }
2013 }
2014 }
2015
2016 /**
2017 * Removes redirect added during MailChimp plugin's activation.
2018 *
2019 * @param string $option Option name.
2020 * @param string $value Option value.
2021 */
2022 public static function remove_mailchimps_redirect( $option, $value ) {
2023 // Remove this action to prevent infinite looping.
2024 remove_action( 'add_option_mailchimp_woocommerce_plugin_do_activation_redirect', array( __CLASS__, 'remove_mailchimps_redirect' ) );
2025
2026 // Update redirect back to false.
2027 update_option( 'mailchimp_woocommerce_plugin_do_activation_redirect', false );
2028 }
2029
2030 /**
2031 * Install a theme from .org in the background via a cron job (used by installer - opt in).
2032 *
2033 * @param string $theme_slug Theme slug.
2034 *
2035 * @throws Exception If unable to proceed with theme installation.
2036 * @since 3.1.0
2037 */
2038 public static function theme_background_installer( $theme_slug ) {
2039 // Explicitly clear the event.
2040 $args = func_get_args();
2041
2042 if ( ! empty( $theme_slug ) ) {
2043 // Suppress feedback.
2044 ob_start();
2045
2046 try {
2047 $theme = wp_get_theme( $theme_slug );
2048
2049 if ( ! $theme->exists() ) {
2050 require_once ABSPATH . 'wp-admin/includes/file.php';
2051 include_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
2052 include_once ABSPATH . 'wp-admin/includes/theme.php';
2053
2054 WP_Filesystem();
2055
2056 $skin = new Automatic_Upgrader_Skin();
2057 $upgrader = new Theme_Upgrader( $skin );
2058 $api = themes_api(
2059 'theme_information',
2060 array(
2061 'slug' => $theme_slug,
2062 'fields' => array( 'sections' => false ),
2063 )
2064 );
2065 $result = $upgrader->install( $api->download_link );
2066
2067 if ( is_wp_error( $result ) ) {
2068 throw new Exception( $result->get_error_message() );
2069 } elseif ( is_wp_error( $skin->result ) ) {
2070 throw new Exception( $skin->result->get_error_message() );
2071 } elseif ( is_null( $result ) ) {
2072 throw new Exception( 'Unable to connect to the filesystem. Please confirm your credentials.' );
2073 }
2074 }
2075
2076 switch_theme( $theme_slug );
2077 } catch ( Exception $e ) {
2078 WC_Admin_Notices::add_custom_notice(
2079 $theme_slug . '_install_error',
2080 sprintf(
2081 // translators: 1: theme slug, 2: error message, 3: URL to install theme manually.
2082 __( '%1$s could not be installed (%2$s). <a href="%3$s">Please install it manually by clicking here.</a>', 'woocommerce' ),
2083 $theme_slug,
2084 $e->getMessage(),
2085 esc_url( admin_url( 'update.php?action=install-theme&theme=' . $theme_slug . '&_wpnonce=' . wp_create_nonce( 'install-theme_' . $theme_slug ) ) )
2086 )
2087 );
2088 }
2089
2090 // Discard feedback.
2091 ob_end_clean();
2092 }
2093 }
2094
2095 /**
2096 * Sets whether PayPal Standard will be loaded on install.
2097 *
2098 * @since 5.5.0
2099 */
2100 private static function set_paypal_standard_load_eligibility() {
2101 // Initiating the payment gateways sets the flag.
2102 if ( class_exists( 'WC_Gateway_Paypal' ) ) {
2103 ( new WC_Gateway_Paypal() )->should_load();
2104 }
2105 }
2106
2107 /**
2108 * Gets the content of the sample refunds and return policy page.
2109 *
2110 * @since 5.6.0
2111 * @return string The content for the page
2112 */
2113 private static function get_refunds_return_policy_page_content() {
2114 return <<<EOT
2115 <!-- wp:paragraph -->
2116 <p><b>This is a sample page.</b></p>
2117 <!-- /wp:paragraph -->
2118
2119 <!-- wp:paragraph -->
2120 <h3>Overview</h3>
2121 <!-- /wp:paragraph -->
2122
2123 <!-- wp:paragraph -->
2124 <p>Our refund and returns policy lasts 30 days. If 30 days have passed since your purchase, we can’t offer you a full refund or exchange.</p>
2125 <!-- /wp:paragraph -->
2126
2127 <!-- wp:paragraph -->
2128 <p>To be eligible for a return, your item must be unused and in the same condition that you received it. It must also be in the original packaging.</p>
2129 <!-- /wp:paragraph -->
2130
2131 <!-- wp:paragraph -->
2132 <p>Several types of goods are exempt from being returned. Perishable goods such as food, flowers, newspapers or magazines cannot be returned. We also do not accept products that are intimate or sanitary goods, hazardous materials, or flammable liquids or gases.</p>
2133 <!-- /wp:paragraph -->
2134
2135 <!-- wp:paragraph -->
2136 <p>Additional non-returnable items:</p>
2137 <!-- /wp:paragraph -->
2138
2139 <!-- wp:list -->
2140 <ul>
2141 <li>Gift cards</li>
2142 <li>Downloadable software products</li>
2143 <li>Some health and personal care items</li>
2144 </ul>
2145 <!-- /wp:list -->
2146
2147 <!-- wp:paragraph -->
2148 <p>To complete your return, we require a receipt or proof of purchase.</p>
2149 <!-- /wp:paragraph -->
2150
2151 <!-- wp:paragraph -->
2152 <p>Please do not send your purchase back to the manufacturer.</p>
2153 <!-- /wp:paragraph -->
2154
2155 <!-- wp:paragraph -->
2156 <p>There are certain situations where only partial refunds are granted:</p>
2157 <!-- /wp:paragraph -->
2158
2159 <!-- wp:list -->
2160 <ul>
2161 <li>Book with obvious signs of use</li>
2162 <li>CD, DVD, VHS tape, software, video game, cassette tape, or vinyl record that has been opened.</li>
2163 <li>Any item not in its original condition, is damaged or missing parts for reasons not due to our error.</li>
2164 <li>Any item that is returned more than 30 days after delivery</li>
2165 </ul>
2166 <!-- /wp:list -->
2167
2168 <!-- wp:paragraph -->
2169 <h2>Refunds</h2>
2170 <!-- /wp:paragraph -->
2171
2172 <!-- wp:paragraph -->
2173 <p>Once your return is received and inspected, we will send you an email to notify you that we have received your returned item. We will also notify you of the approval or rejection of your refund.</p>
2174 <!-- /wp:paragraph -->
2175
2176 <!-- wp:paragraph -->
2177 <p>If you are approved, then your refund will be processed, and a credit will automatically be applied to your credit card or original method of payment, within a certain amount of days.</p>
2178 <!-- /wp:paragraph -->
2179
2180 <!-- wp:paragraph -->
2181 <b>Late or missing refunds</b>
2182 <!-- /wp:paragraph -->
2183
2184 <!-- wp:paragraph -->
2185 <p>If you haven’t received a refund yet, first check your bank account again.</p>
2186 <!-- /wp:paragraph -->
2187
2188 <!-- wp:paragraph -->
2189 <p>Then contact your credit card company, it may take some time before your refund is officially posted.</p>
2190 <!-- /wp:paragraph -->
2191
2192 <!-- wp:paragraph -->
2193 <p>Next contact your bank. There is often some processing time before a refund is posted.</p>
2194 <!-- /wp:paragraph -->
2195
2196 <!-- wp:paragraph -->
2197 <p>If you’ve done all of this and you still have not received your refund yet, please contact us at {email address}.</p>
2198 <!-- /wp:paragraph -->
2199
2200 <!-- wp:paragraph -->
2201 <b>Sale items</b>
2202 <!-- /wp:paragraph -->
2203
2204 <!-- wp:paragraph -->
2205 <p>Only regular priced items may be refunded. Sale items cannot be refunded.</p>
2206 <!-- /wp:paragraph -->
2207
2208 <!-- wp:paragraph -->
2209 <h2>Exchanges</h2>
2210 <!-- /wp:paragraph -->
2211
2212 <!-- wp:paragraph -->
2213 <p>We only replace items if they are defective or damaged. If you need to exchange it for the same item, send us an email at {email address} and send your item to: {physical address}.</p>
2214 <!-- /wp:paragraph -->
2215
2216 <!-- wp:paragraph -->
2217 <h2>Gifts</h2>
2218 <!-- /wp:paragraph -->
2219
2220 <!-- wp:paragraph -->
2221 <p>If the item was marked as a gift when purchased and shipped directly to you, you’ll receive a gift credit for the value of your return. Once the returned item is received, a gift certificate will be mailed to you.</p>
2222 <!-- /wp:paragraph -->
2223
2224 <!-- wp:paragraph -->
2225 <p>If the item wasn’t marked as a gift when purchased, or the gift giver had the order shipped to themselves to give to you later, we will send a refund to the gift giver and they will find out about your return.</p>
2226 <!-- /wp:paragraph -->
2227
2228 <!-- wp:paragraph -->
2229 <h2>Shipping returns</h2>
2230 <!-- /wp:paragraph -->
2231
2232 <!-- wp:paragraph -->
2233 <p>To return your product, you should mail your product to: {physical address}.</p>
2234 <!-- /wp:paragraph -->
2235
2236 <!-- wp:paragraph -->
2237 <p>You will be responsible for paying for your own shipping costs for returning your item. Shipping costs are non-refundable. If you receive a refund, the cost of return shipping will be deducted from your refund.</p>
2238 <!-- /wp:paragraph -->
2239
2240 <!-- wp:paragraph -->
2241 <p>Depending on where you live, the time it may take for your exchanged product to reach you may vary.</p>
2242 <!-- /wp:paragraph -->
2243
2244 <!-- wp:paragraph -->
2245 <p>If you are returning more expensive items, you may consider using a trackable shipping service or purchasing shipping insurance. We don’t guarantee that we will receive your returned item.</p>
2246 <!-- /wp:paragraph -->
2247
2248 <!-- wp:paragraph -->
2249 <h2>Need help?</h2>
2250 <!-- /wp:paragraph -->
2251
2252 <!-- wp:paragraph -->
2253 <p>Contact us at {email} for questions related to refunds and returns.</p>
2254 <!-- /wp:paragraph -->
2255 EOT;
2256 }
2257
2258 /**
2259 * Adds an admin inbox note after a page has been created to notify
2260 * user. For example to take action to edit the page such as the
2261 * Refund and returns page.
2262 *
2263 * @since 5.6.0
2264 * @return void
2265 */
2266 public static function add_admin_note_after_page_created() {
2267 if ( ! WC()->is_wc_admin_active() ) {
2268 return;
2269 }
2270
2271 $page_id = get_option( 'woocommerce_refund_returns_page_created', null );
2272
2273 if ( null === $page_id ) {
2274 return;
2275 }
2276
2277 WC_Notes_Refund_Returns::possibly_add_note( $page_id );
2278 }
2279
2280 /**
2281 * When pages are created, we might want to take some action.
2282 * In this case we want to set an option when refund and returns
2283 * page is created.
2284 *
2285 * @since 5.6.0
2286 * @param int $page_id ID of the page.
2287 * @param array $page_data The data of the page created.
2288 * @return void
2289 */
2290 public static function page_created( $page_id, $page_data ) {
2291 if ( 'refund_returns' === $page_data['post_name'] ) {
2292 delete_option( 'woocommerce_refund_returns_page_created' );
2293 add_option( 'woocommerce_refund_returns_page_created', $page_id, '', false );
2294 }
2295 }
2296 }
2297
2298 WC_Install::init();
2299