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