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