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