PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 9.6.4
WooCommerce v9.6.4
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 / wc-update-functions.php
woocommerce / includes Last commit date
abstracts 1 year ago admin 1 year ago blocks 1 year ago cli 1 year ago customizer 2 years ago data-stores 1 year ago emails 1 year ago export 1 year ago gateways 1 year ago import 1 year ago integrations 2 years ago interfaces 1 year ago legacy 1 year ago libraries 1 year ago log-handlers 2 years ago payment-tokens 5 years ago product-usage 1 year ago queue 4 years ago react-admin 1 year ago rest-api 1 year ago shipping 1 year ago shortcodes 1 year ago theme-support 2 years ago tracks 1 year ago traits 5 years ago walkers 5 years ago wccom-site 1 year ago widgets 1 year ago class-wc-ajax.php 2 years ago class-wc-auth.php 1 year ago class-wc-autoloader.php 1 year ago class-wc-background-emailer.php 5 years ago class-wc-background-updater.php 5 years ago class-wc-brands-brand-settings-manager.php 1 year ago class-wc-brands-coupons.php 1 year ago class-wc-brands.php 1 year ago class-wc-breadcrumb.php 5 years ago class-wc-cache-helper.php 1 year ago class-wc-cart-fees.php 2 years ago class-wc-cart-session.php 1 year ago class-wc-cart-totals.php 2 years 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 3 years ago class-wc-countries.php 1 year ago class-wc-coupon.php 1 year ago class-wc-customer-download-log.php 5 years ago class-wc-customer-download.php 1 year ago class-wc-customer.php 2 years ago class-wc-data-exception.php 8 years ago class-wc-data-store.php 3 years ago class-wc-datetime.php 4 years ago class-wc-deprecated-action-hooks.php 2 years ago class-wc-deprecated-filter-hooks.php 3 years 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 5 years 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 6 years ago class-wc-geolocation.php 1 year ago class-wc-https.php 2 years ago class-wc-install.php 1 year ago class-wc-integrations.php 5 years ago class-wc-log-levels.php 2 years ago class-wc-logger.php 1 year ago class-wc-meta-data.php 4 years ago class-wc-order-factory.php 2 years ago class-wc-order-item-coupon.php 4 years ago class-wc-order-item-fee.php 1 year ago class-wc-order-item-meta.php 4 years 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 4 years ago class-wc-order-item.php 1 year ago class-wc-order-query.php 4 years 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 3 years ago class-wc-post-data.php 1 year ago class-wc-post-types.php 1 year ago class-wc-privacy-background-process.php 5 years ago class-wc-privacy-erasers.php 1 year ago class-wc-privacy-exporters.php 4 years ago class-wc-privacy.php 1 year ago class-wc-product-attribute.php 4 years ago class-wc-product-download.php 2 years ago class-wc-product-external.php 5 years ago class-wc-product-factory.php 2 years ago class-wc-product-grouped.php 8 years ago class-wc-product-query.php 5 years 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 4 years ago class-wc-regenerate-images-request.php 3 years ago class-wc-regenerate-images.php 1 year ago class-wc-register-wp-admin-settings.php 4 years ago class-wc-rest-authentication.php 1 year ago class-wc-rest-exception.php 5 years ago class-wc-session-handler.php 2 years ago class-wc-shipping-rate.php 1 year ago class-wc-shipping-zone.php 5 years ago class-wc-shipping-zones.php 5 years ago class-wc-shipping.php 4 years ago class-wc-shortcodes.php 2 years ago class-wc-structured-data.php 1 year ago class-wc-tax.php 2 years ago class-wc-template-loader.php 2 years ago class-wc-tracker.php 1 year ago class-wc-validation.php 2 years ago class-wc-webhook.php 1 year ago class-woocommerce.php 3 months ago wc-account-functions.php 1 year ago wc-attribute-functions.php 1 year ago wc-brands-functions.php 1 year ago wc-cart-functions.php 1 year ago wc-conditional-functions.php 2 years ago wc-core-functions.php 1 year ago wc-coupon-functions.php 3 years ago wc-deprecated-functions.php 2 years ago wc-formatting-functions.php 1 year ago wc-notice-functions.php 2 years ago wc-order-functions.php 1 year ago wc-order-item-functions.php 3 years 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 3 years 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 5 years ago
wc-update-functions.php
2946 lines
1 <?php
2 /**
3 * WooCommerce Updates
4 *
5 * Functions for updating data, used by the background updater. These functions must be included
6 * in the list returned by WC_Install::get_db_update_callbacks.
7 *
8 * Please note that these functions are invoked when WooCommerce is updated from a previous version,
9 * but NOT when WooCommerce is newly installed.
10 *
11 * Database schema changes must be incorporated to the SQL returned by WC_Install::get_schema, which is applied
12 * via dbDelta at both install and update time. If any other kind of database change is required
13 * at install time (e.g. populating tables), use the 'woocommerce_installed' hook.
14 *
15 * @package WooCommerce\Functions
16 * @version 3.3.0
17 */
18
19 defined( 'ABSPATH' ) || exit;
20
21 use Automattic\WooCommerce\Admin\Notes\Note;
22 use Automattic\WooCommerce\Admin\Notes\Notes;
23 use Automattic\WooCommerce\Database\Migrations\MigrationHelper;
24 use Automattic\WooCommerce\Internal\Admin\Marketing\MarketingSpecs;
25 use Automattic\WooCommerce\Internal\Admin\Notes\WooSubscriptionsNotes;
26 use Automattic\WooCommerce\Internal\AssignDefaultCategory;
27 use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;
28 use Automattic\WooCommerce\Internal\DataStores\Orders\DataSynchronizer;
29 use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
30 use Automattic\WooCommerce\Internal\ProductAttributesLookup\DataRegenerator;
31 use Automattic\WooCommerce\Internal\ProductAttributesLookup\LookupDataStore;
32 use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Register as Download_Directories;
33 use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Synchronize as Download_Directories_Sync;
34 use Automattic\WooCommerce\Internal\Utilities\DatabaseUtil;
35 use Automattic\WooCommerce\Utilities\StringUtil;
36
37 /**
38 * Update file paths for 2.0
39 *
40 * @return void
41 */
42 function wc_update_200_file_paths() {
43 global $wpdb;
44
45 // Upgrade old style files paths to support multiple file paths.
46 $existing_file_paths = $wpdb->get_results( "SELECT meta_value, meta_id, post_id FROM {$wpdb->postmeta} WHERE meta_key = '_file_path' AND meta_value != '';" );
47
48 if ( $existing_file_paths ) {
49
50 foreach ( $existing_file_paths as $existing_file_path ) {
51
52 $old_file_path = trim( $existing_file_path->meta_value );
53
54 if ( ! empty( $old_file_path ) ) {
55 // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
56 $file_paths = serialize( array( md5( $old_file_path ) => $old_file_path ) );
57
58 $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->postmeta} SET meta_key = '_file_paths', meta_value = %s WHERE meta_id = %d", $file_paths, $existing_file_path->meta_id ) );
59
60 $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->prefix}woocommerce_downloadable_product_permissions SET download_id = %s WHERE product_id = %d", md5( $old_file_path ), $existing_file_path->post_id ) );
61
62 }
63 }
64 }
65 }
66
67 /**
68 * Update permalinks for 2.0
69 *
70 * @return void
71 */
72 function wc_update_200_permalinks() {
73 // Setup default permalinks if shop page is defined.
74 $permalinks = get_option( 'woocommerce_permalinks' );
75 $shop_page_id = wc_get_page_id( 'shop' );
76
77 if ( empty( $permalinks ) && $shop_page_id > 0 ) {
78
79 $base_slug = $shop_page_id > 0 && get_post( $shop_page_id ) ? get_page_uri( $shop_page_id ) : 'shop';
80
81 $category_base = 'yes' === get_option( 'woocommerce_prepend_shop_page_to_urls' ) ? trailingslashit( $base_slug ) : '';
82 $category_slug = get_option( 'woocommerce_product_category_slug' ) ? get_option( 'woocommerce_product_category_slug' ) : _x( 'product-category', 'slug', 'woocommerce' );
83 $tag_slug = get_option( 'woocommerce_product_tag_slug' ) ? get_option( 'woocommerce_product_tag_slug' ) : _x( 'product-tag', 'slug', 'woocommerce' );
84
85 if ( 'yes' === get_option( 'woocommerce_prepend_shop_page_to_products' ) ) {
86 $product_base = trailingslashit( $base_slug );
87 } else {
88 $product_slug = get_option( 'woocommerce_product_slug' );
89 if ( false !== $product_slug && ! empty( $product_slug ) ) {
90 $product_base = trailingslashit( $product_slug );
91 } else {
92 $product_base = trailingslashit( _x( 'product', 'slug', 'woocommerce' ) );
93 }
94 }
95
96 if ( 'yes' === get_option( 'woocommerce_prepend_category_to_products' ) ) {
97 $product_base .= trailingslashit( '%product_cat%' );
98 }
99
100 $permalinks = array(
101 'product_base' => untrailingslashit( $product_base ),
102 'category_base' => untrailingslashit( $category_base . $category_slug ),
103 'attribute_base' => untrailingslashit( $category_base ),
104 'tag_base' => untrailingslashit( $category_base . $tag_slug ),
105 );
106
107 update_option( 'woocommerce_permalinks', $permalinks );
108 }
109 }
110
111 /**
112 * Update sub-category display options for 2.0
113 *
114 * @return void
115 */
116 function wc_update_200_subcat_display() {
117 // Update subcat display settings.
118 if ( 'yes' === get_option( 'woocommerce_shop_show_subcategories' ) ) {
119 if ( 'yes' === get_option( 'woocommerce_hide_products_when_showing_subcategories' ) ) {
120 update_option( 'woocommerce_shop_page_display', 'subcategories' );
121 } else {
122 update_option( 'woocommerce_shop_page_display', 'both' );
123 }
124 }
125
126 if ( 'yes' === get_option( 'woocommerce_show_subcategories' ) ) {
127 if ( 'yes' === get_option( 'woocommerce_hide_products_when_showing_subcategories' ) ) {
128 update_option( 'woocommerce_category_archive_display', 'subcategories' );
129 } else {
130 update_option( 'woocommerce_category_archive_display', 'both' );
131 }
132 }
133 }
134
135 /**
136 * Update tax rates for 2.0
137 *
138 * @return void
139 */
140 function wc_update_200_taxrates() {
141 global $wpdb;
142
143 // Update tax rates.
144 $loop = 0;
145 $tax_rates = get_option( 'woocommerce_tax_rates' );
146
147 if ( $tax_rates ) {
148 foreach ( $tax_rates as $tax_rate ) {
149
150 foreach ( $tax_rate['countries'] as $country => $states ) {
151
152 $states = array_reverse( $states );
153
154 foreach ( $states as $state ) {
155
156 if ( '*' === $state ) {
157 $state = '';
158 }
159
160 $wpdb->insert(
161 $wpdb->prefix . 'woocommerce_tax_rates',
162 array(
163 'tax_rate_country' => $country,
164 'tax_rate_state' => $state,
165 'tax_rate' => $tax_rate['rate'],
166 'tax_rate_name' => $tax_rate['label'],
167 'tax_rate_priority' => 1,
168 'tax_rate_compound' => ( 'yes' === $tax_rate['compound'] ) ? 1 : 0,
169 'tax_rate_shipping' => ( 'yes' === $tax_rate['shipping'] ) ? 1 : 0,
170 'tax_rate_order' => $loop,
171 'tax_rate_class' => $tax_rate['class'],
172 )
173 );
174
175 ++$loop;
176 }
177 }
178 }
179 }
180
181 $local_tax_rates = get_option( 'woocommerce_local_tax_rates' );
182
183 if ( $local_tax_rates ) {
184 foreach ( $local_tax_rates as $tax_rate ) {
185
186 $location_type = ( 'postcode' === $tax_rate['location_type'] ) ? 'postcode' : 'city';
187
188 if ( '*' === $tax_rate['state'] ) {
189 $tax_rate['state'] = '';
190 }
191
192 $wpdb->insert(
193 $wpdb->prefix . 'woocommerce_tax_rates',
194 array(
195 'tax_rate_country' => $tax_rate['country'],
196 'tax_rate_state' => $tax_rate['state'],
197 'tax_rate' => $tax_rate['rate'],
198 'tax_rate_name' => $tax_rate['label'],
199 'tax_rate_priority' => 2,
200 'tax_rate_compound' => ( 'yes' === $tax_rate['compound'] ) ? 1 : 0,
201 'tax_rate_shipping' => ( 'yes' === $tax_rate['shipping'] ) ? 1 : 0,
202 'tax_rate_order' => $loop,
203 'tax_rate_class' => $tax_rate['class'],
204 )
205 );
206
207 $tax_rate_id = $wpdb->insert_id;
208
209 if ( $tax_rate['locations'] ) {
210 foreach ( $tax_rate['locations'] as $location ) {
211
212 $wpdb->insert(
213 $wpdb->prefix . 'woocommerce_tax_rate_locations',
214 array(
215 'location_code' => $location,
216 'tax_rate_id' => $tax_rate_id,
217 'location_type' => $location_type,
218 )
219 );
220
221 }
222 }
223
224 ++$loop;
225 }
226 }
227
228 update_option( 'woocommerce_tax_rates_backup', $tax_rates );
229 update_option( 'woocommerce_local_tax_rates_backup', $local_tax_rates );
230 delete_option( 'woocommerce_tax_rates' );
231 delete_option( 'woocommerce_local_tax_rates' );
232 }
233
234 /**
235 * Update order item line items for 2.0
236 *
237 * @return void
238 */
239 function wc_update_200_line_items() {
240 global $wpdb;
241
242 // Now its time for the massive update to line items - move them to the new DB tables.
243 // Reverse with UPDATE `wpwc_postmeta` SET meta_key = '_order_items' WHERE meta_key = '_order_items_old'.
244 $order_item_rows = $wpdb->get_results(
245 "SELECT meta_value, post_id FROM {$wpdb->postmeta} WHERE meta_key = '_order_items'"
246 );
247
248 foreach ( $order_item_rows as $order_item_row ) {
249
250 $order_items = (array) maybe_unserialize( $order_item_row->meta_value );
251
252 foreach ( $order_items as $order_item ) {
253
254 if ( ! isset( $order_item['line_total'] ) && isset( $order_item['taxrate'] ) && isset( $order_item['cost'] ) ) {
255 $order_item['line_tax'] = number_format( ( $order_item['cost'] * $order_item['qty'] ) * ( $order_item['taxrate'] / 100 ), 2, '.', '' );
256 $order_item['line_total'] = $order_item['cost'] * $order_item['qty'];
257 $order_item['line_subtotal_tax'] = $order_item['line_tax'];
258 $order_item['line_subtotal'] = $order_item['line_total'];
259 }
260
261 $order_item['line_tax'] = isset( $order_item['line_tax'] ) ? $order_item['line_tax'] : 0;
262 $order_item['line_total'] = isset( $order_item['line_total'] ) ? $order_item['line_total'] : 0;
263 $order_item['line_subtotal_tax'] = isset( $order_item['line_subtotal_tax'] ) ? $order_item['line_subtotal_tax'] : 0;
264 $order_item['line_subtotal'] = isset( $order_item['line_subtotal'] ) ? $order_item['line_subtotal'] : 0;
265
266 $item_id = wc_add_order_item(
267 $order_item_row->post_id,
268 array(
269 'order_item_name' => $order_item['name'],
270 'order_item_type' => 'line_item',
271 )
272 );
273
274 // Add line item meta.
275 if ( $item_id ) {
276 wc_add_order_item_meta( $item_id, '_qty', absint( $order_item['qty'] ) );
277 wc_add_order_item_meta( $item_id, '_tax_class', $order_item['tax_class'] );
278 wc_add_order_item_meta( $item_id, '_product_id', $order_item['id'] );
279 wc_add_order_item_meta( $item_id, '_variation_id', $order_item['variation_id'] );
280 wc_add_order_item_meta( $item_id, '_line_subtotal', wc_format_decimal( $order_item['line_subtotal'] ) );
281 wc_add_order_item_meta( $item_id, '_line_subtotal_tax', wc_format_decimal( $order_item['line_subtotal_tax'] ) );
282 wc_add_order_item_meta( $item_id, '_line_total', wc_format_decimal( $order_item['line_total'] ) );
283 wc_add_order_item_meta( $item_id, '_line_tax', wc_format_decimal( $order_item['line_tax'] ) );
284
285 $meta_rows = array();
286
287 // Insert meta.
288 if ( ! empty( $order_item['item_meta'] ) ) {
289 foreach ( $order_item['item_meta'] as $key => $meta ) {
290 // Backwards compatibility.
291 if ( is_array( $meta ) && isset( $meta['meta_name'] ) ) {
292 $meta_rows[] = '(' . $item_id . ',"' . esc_sql( $meta['meta_name'] ) . '","' . esc_sql( $meta['meta_value'] ) . '")';
293 } else {
294 $meta_rows[] = '(' . $item_id . ',"' . esc_sql( $key ) . '","' . esc_sql( $meta ) . '")';
295 }
296 }
297 }
298
299 // Insert meta rows at once.
300 if ( count( $meta_rows ) > 0 ) {
301 $wpdb->query(
302 $wpdb->prepare(
303 "INSERT INTO {$wpdb->prefix}woocommerce_order_itemmeta ( order_item_id, meta_key, meta_value )
304 VALUES " . implode( ',', $meta_rows ) . ';', // @codingStandardsIgnoreLine
305 $order_item_row->post_id
306 )
307 );
308 }
309
310 // Delete from DB (rename).
311 $wpdb->query(
312 $wpdb->prepare(
313 "UPDATE {$wpdb->postmeta}
314 SET meta_key = '_order_items_old'
315 WHERE meta_key = '_order_items'
316 AND post_id = %d",
317 $order_item_row->post_id
318 )
319 );
320 }
321
322 unset( $meta_rows, $item_id, $order_item );
323 }
324 }
325
326 // Do the same kind of update for order_taxes - move to lines.
327 // Reverse with UPDATE `wpwc_postmeta` SET meta_key = '_order_taxes' WHERE meta_key = '_order_taxes_old'.
328 $order_tax_rows = $wpdb->get_results(
329 "SELECT meta_value, post_id FROM {$wpdb->postmeta}
330 WHERE meta_key = '_order_taxes'"
331 );
332
333 foreach ( $order_tax_rows as $order_tax_row ) {
334
335 $order_taxes = (array) maybe_unserialize( $order_tax_row->meta_value );
336
337 if ( ! empty( $order_taxes ) ) {
338 foreach ( $order_taxes as $order_tax ) {
339
340 if ( ! isset( $order_tax['label'] ) || ! isset( $order_tax['cart_tax'] ) || ! isset( $order_tax['shipping_tax'] ) ) {
341 continue;
342 }
343
344 $item_id = wc_add_order_item(
345 $order_tax_row->post_id,
346 array(
347 'order_item_name' => $order_tax['label'],
348 'order_item_type' => 'tax',
349 )
350 );
351
352 // Add line item meta.
353 if ( $item_id ) {
354 wc_add_order_item_meta( $item_id, 'compound', absint( isset( $order_tax['compound'] ) ? $order_tax['compound'] : 0 ) );
355 wc_add_order_item_meta( $item_id, 'tax_amount', wc_clean( $order_tax['cart_tax'] ) );
356 wc_add_order_item_meta( $item_id, 'shipping_tax_amount', wc_clean( $order_tax['shipping_tax'] ) );
357 }
358
359 // Delete from DB (rename).
360 $wpdb->query(
361 $wpdb->prepare(
362 "UPDATE {$wpdb->postmeta}
363 SET meta_key = '_order_taxes_old'
364 WHERE meta_key = '_order_taxes'
365 AND post_id = %d",
366 $order_tax_row->post_id
367 )
368 );
369 }
370 }
371 }
372 }
373
374 /**
375 * Update image settings for 2.0
376 *
377 * @return void
378 */
379 function wc_update_200_images() {
380 // Grab the pre 2.0 Image options and use to populate the new image options settings,
381 // cleaning up afterwards like nice people do.
382 foreach ( array( 'catalog', 'single', 'thumbnail' ) as $value ) {
383
384 $old_settings = array_filter(
385 array(
386 'width' => get_option( 'woocommerce_' . $value . '_image_width' ),
387 'height' => get_option( 'woocommerce_' . $value . '_image_height' ),
388 'crop' => get_option( 'woocommerce_' . $value . '_image_crop' ),
389 )
390 );
391
392 if ( ! empty( $old_settings ) && update_option( 'shop_' . $value . '_image_size', $old_settings ) ) {
393
394 delete_option( 'woocommerce_' . $value . '_image_width' );
395 delete_option( 'woocommerce_' . $value . '_image_height' );
396 delete_option( 'woocommerce_' . $value . '_image_crop' );
397
398 }
399 }
400 }
401
402 /**
403 * Update DB version for 2.0
404 *
405 * @return void
406 */
407 function wc_update_200_db_version() {
408 WC_Install::update_db_version( '2.0.0' );
409 }
410
411 /**
412 * Update Brazilian States for 2.0.9
413 *
414 * @return void
415 */
416 function wc_update_209_brazillian_state() {
417 global $wpdb;
418
419 // phpcs:disable WordPress.DB.SlowDBQuery
420
421 // Update Brazilian state codes.
422 $wpdb->update(
423 $wpdb->postmeta,
424 array(
425 'meta_value' => 'BA',
426 ),
427 array(
428 'meta_key' => '_billing_state',
429 'meta_value' => 'BH',
430 )
431 );
432 $wpdb->update(
433 $wpdb->postmeta,
434 array(
435 'meta_value' => 'BA',
436 ),
437 array(
438 'meta_key' => '_shipping_state',
439 'meta_value' => 'BH',
440 )
441 );
442 $wpdb->update(
443 $wpdb->usermeta,
444 array(
445 'meta_value' => 'BA',
446 ),
447 array(
448 'meta_key' => 'billing_state',
449 'meta_value' => 'BH',
450 )
451 );
452 $wpdb->update(
453 $wpdb->usermeta,
454 array(
455 'meta_value' => 'BA',
456 ),
457 array(
458 'meta_key' => 'shipping_state',
459 'meta_value' => 'BH',
460 )
461 );
462
463 // phpcs:enable WordPress.DB.SlowDBQuery
464 }
465
466 /**
467 * Update DB version for 2.0.9
468 *
469 * @return void
470 */
471 function wc_update_209_db_version() {
472 WC_Install::update_db_version( '2.0.9' );
473 }
474
475 /**
476 * Remove pages for 2.1
477 *
478 * @return void
479 */
480 function wc_update_210_remove_pages() {
481 // Pages no longer used.
482 wp_trash_post( get_option( 'woocommerce_pay_page_id' ) );
483 wp_trash_post( get_option( 'woocommerce_thanks_page_id' ) );
484 wp_trash_post( get_option( 'woocommerce_view_order_page_id' ) );
485 wp_trash_post( get_option( 'woocommerce_change_password_page_id' ) );
486 wp_trash_post( get_option( 'woocommerce_edit_address_page_id' ) );
487 wp_trash_post( get_option( 'woocommerce_lost_password_page_id' ) );
488 }
489
490 /**
491 * Update file paths to support multiple files for 2.1
492 *
493 * @return void
494 */
495 function wc_update_210_file_paths() {
496 global $wpdb;
497
498 // Upgrade file paths to support multiple file paths + names etc.
499 $existing_file_paths = $wpdb->get_results( "SELECT meta_value, meta_id FROM {$wpdb->postmeta} WHERE meta_key = '_file_paths' AND meta_value != '';" );
500
501 if ( $existing_file_paths ) {
502
503 foreach ( $existing_file_paths as $existing_file_path ) {
504
505 $needs_update = false;
506 $new_value = array();
507 $value = maybe_unserialize( trim( $existing_file_path->meta_value ) );
508
509 if ( $value ) {
510 foreach ( $value as $key => $file ) {
511 if ( ! is_array( $file ) ) {
512 $needs_update = true;
513 $new_value[ $key ] = array(
514 'file' => $file,
515 'name' => wc_get_filename_from_url( $file ),
516 );
517 } else {
518 $new_value[ $key ] = $file;
519 }
520 }
521 if ( $needs_update ) {
522 // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
523 $new_value = serialize( $new_value );
524
525 $wpdb->query( $wpdb->prepare( "UPDATE {$wpdb->postmeta} SET meta_key = %s, meta_value = %s WHERE meta_id = %d", '_downloadable_files', $new_value, $existing_file_path->meta_id ) );
526 }
527 }
528 }
529 }
530 }
531
532 /**
533 * Update DB version for 2.1
534 *
535 * @return void
536 */
537 function wc_update_210_db_version() {
538 WC_Install::update_db_version( '2.1.0' );
539 }
540
541 /**
542 * Update shipping options for 2.2
543 *
544 * @return void
545 */
546 function wc_update_220_shipping() {
547 $woocommerce_ship_to_destination = 'shipping';
548
549 if ( get_option( 'woocommerce_ship_to_billing_address_only' ) === 'yes' ) {
550 $woocommerce_ship_to_destination = 'billing_only';
551 } elseif ( get_option( 'woocommerce_ship_to_billing' ) === 'yes' ) {
552 $woocommerce_ship_to_destination = 'billing';
553 }
554
555 add_option( 'woocommerce_ship_to_destination', $woocommerce_ship_to_destination, '', 'no' );
556 }
557
558 /**
559 * Update order statuses for 2.2
560 *
561 * Keeping the internal statuses names as strings to avoid regression issues (not referencing Automattic\WooCommerce\Enums\OrderInternalStatus class).
562 *
563 * @return void
564 */
565 function wc_update_220_order_status() {
566 global $wpdb;
567 $wpdb->query(
568 "UPDATE {$wpdb->posts} as posts
569 LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_id
570 LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )
571 LEFT JOIN {$wpdb->terms} AS term USING( term_id )
572 SET posts.post_status = 'wc-pending'
573 WHERE posts.post_type = 'shop_order'
574 AND posts.post_status = 'publish'
575 AND tax.taxonomy = 'shop_order_status'
576 AND term.slug LIKE 'pending%';"
577 );
578 $wpdb->query(
579 "UPDATE {$wpdb->posts} as posts
580 LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_id
581 LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )
582 LEFT JOIN {$wpdb->terms} AS term USING( term_id )
583 SET posts.post_status = 'wc-processing'
584 WHERE posts.post_type = 'shop_order'
585 AND posts.post_status = 'publish'
586 AND tax.taxonomy = 'shop_order_status'
587 AND term.slug LIKE 'processing%';"
588 );
589 $wpdb->query(
590 "UPDATE {$wpdb->posts} as posts
591 LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_id
592 LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )
593 LEFT JOIN {$wpdb->terms} AS term USING( term_id )
594 SET posts.post_status = 'wc-on-hold'
595 WHERE posts.post_type = 'shop_order'
596 AND posts.post_status = 'publish'
597 AND tax.taxonomy = 'shop_order_status'
598 AND term.slug LIKE 'on-hold%';"
599 );
600 $wpdb->query(
601 "UPDATE {$wpdb->posts} as posts
602 LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_id
603 LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )
604 LEFT JOIN {$wpdb->terms} AS term USING( term_id )
605 SET posts.post_status = 'wc-completed'
606 WHERE posts.post_type = 'shop_order'
607 AND posts.post_status = 'publish'
608 AND tax.taxonomy = 'shop_order_status'
609 AND term.slug LIKE 'completed%';"
610 );
611 $wpdb->query(
612 "UPDATE {$wpdb->posts} as posts
613 LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_id
614 LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )
615 LEFT JOIN {$wpdb->terms} AS term USING( term_id )
616 SET posts.post_status = 'wc-cancelled'
617 WHERE posts.post_type = 'shop_order'
618 AND posts.post_status = 'publish'
619 AND tax.taxonomy = 'shop_order_status'
620 AND term.slug LIKE 'cancelled%';"
621 );
622 $wpdb->query(
623 "UPDATE {$wpdb->posts} as posts
624 LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_id
625 LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )
626 LEFT JOIN {$wpdb->terms} AS term USING( term_id )
627 SET posts.post_status = 'wc-refunded'
628 WHERE posts.post_type = 'shop_order'
629 AND posts.post_status = 'publish'
630 AND tax.taxonomy = 'shop_order_status'
631 AND term.slug LIKE 'refunded%';"
632 );
633 $wpdb->query(
634 "UPDATE {$wpdb->posts} as posts
635 LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_id
636 LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )
637 LEFT JOIN {$wpdb->terms} AS term USING( term_id )
638 SET posts.post_status = 'wc-failed'
639 WHERE posts.post_type = 'shop_order'
640 AND posts.post_status = 'publish'
641 AND tax.taxonomy = 'shop_order_status'
642 AND term.slug LIKE 'failed%';"
643 );
644 }
645
646 /**
647 * Update variations for 2.2
648 *
649 * @return void
650 */
651 function wc_update_220_variations() {
652 global $wpdb;
653 // Update variations which manage stock.
654 $update_variations = $wpdb->get_results(
655 "SELECT DISTINCT posts.ID AS variation_id, posts.post_parent AS variation_parent FROM {$wpdb->posts} as posts
656 LEFT OUTER JOIN {$wpdb->postmeta} AS postmeta ON posts.ID = postmeta.post_id AND postmeta.meta_key = '_stock'
657 LEFT OUTER JOIN {$wpdb->postmeta} as postmeta2 ON posts.ID = postmeta2.post_id AND postmeta2.meta_key = '_manage_stock'
658 WHERE posts.post_type = 'product_variation'
659 AND postmeta.meta_value IS NOT NULL
660 AND postmeta.meta_value != ''
661 AND postmeta2.meta_value IS NULL"
662 );
663
664 foreach ( $update_variations as $variation ) {
665 $parent_backorders = get_post_meta( $variation->variation_parent, '_backorders', true );
666 add_post_meta( $variation->variation_id, '_manage_stock', 'yes', true );
667 add_post_meta( $variation->variation_id, '_backorders', $parent_backorders ? $parent_backorders : 'no', true );
668 }
669 }
670
671 /**
672 * Update attributes for 2.2
673 *
674 * @return void
675 */
676 function wc_update_220_attributes() {
677 global $wpdb;
678 // Update taxonomy names with correct sanitized names.
679 $attribute_taxonomies = $wpdb->get_results( 'SELECT attribute_name, attribute_id FROM ' . $wpdb->prefix . 'woocommerce_attribute_taxonomies' );
680
681 foreach ( $attribute_taxonomies as $attribute_taxonomy ) {
682 $sanitized_attribute_name = wc_sanitize_taxonomy_name( $attribute_taxonomy->attribute_name );
683 if ( $sanitized_attribute_name !== $attribute_taxonomy->attribute_name ) {
684 if ( ! $wpdb->get_var( $wpdb->prepare( "SELECT 1=1 FROM {$wpdb->prefix}woocommerce_attribute_taxonomies WHERE attribute_name = %s;", $sanitized_attribute_name ) ) ) {
685 // Update attribute.
686 $wpdb->update(
687 "{$wpdb->prefix}woocommerce_attribute_taxonomies",
688 array(
689 'attribute_name' => $sanitized_attribute_name,
690 ),
691 array(
692 'attribute_id' => $attribute_taxonomy->attribute_id,
693 )
694 );
695
696 // Update terms.
697 $wpdb->update(
698 $wpdb->term_taxonomy,
699 array( 'taxonomy' => wc_attribute_taxonomy_name( $sanitized_attribute_name ) ),
700 array( 'taxonomy' => 'pa_' . $attribute_taxonomy->attribute_name )
701 );
702 }
703 }
704 }
705
706 delete_transient( 'wc_attribute_taxonomies' );
707 WC_Cache_Helper::invalidate_cache_group( 'woocommerce-attributes' );
708 }
709
710 /**
711 * Update DB version for 2.2
712 *
713 * @return void
714 */
715 function wc_update_220_db_version() {
716 WC_Install::update_db_version( '2.2.0' );
717 }
718
719 /**
720 * Update options for 2.3
721 *
722 * @return void
723 */
724 function wc_update_230_options() {
725 // _money_spent and _order_count may be out of sync - clear them
726 delete_metadata( 'user', 0, '_money_spent', '', true );
727 delete_metadata( 'user', 0, '_order_count', '', true );
728 delete_metadata( 'user', 0, '_last_order', '', true );
729
730 // To prevent taxes being hidden when using a default 'no address' in a store with tax inc prices, set the woocommerce_default_customer_address to use the store base address by default.
731 if ( '' === get_option( 'woocommerce_default_customer_address', false ) && wc_prices_include_tax() ) {
732 update_option( 'woocommerce_default_customer_address', 'base' );
733 }
734 }
735
736 /**
737 * Update DB version for 2.3
738 *
739 * @return void
740 */
741 function wc_update_230_db_version() {
742 WC_Install::update_db_version( '2.3.0' );
743 }
744
745 /**
746 * Update calc discount options for 2.4
747 *
748 * @return void
749 */
750 function wc_update_240_options() {
751 /**
752 * Coupon discount calculations.
753 * Maintain the old coupon logic for upgrades.
754 */
755 update_option( 'woocommerce_calc_discounts_sequentially', 'yes' );
756 }
757
758 /**
759 * Update shipping methods for 2.4
760 *
761 * @return void
762 */
763 function wc_update_240_shipping_methods() {
764 /**
765 * Flat Rate Shipping.
766 * Update legacy options to new math based options.
767 */
768 $shipping_methods = array(
769 'woocommerce_flat_rates' => new WC_Shipping_Legacy_Flat_Rate(),
770 'woocommerce_international_delivery_flat_rates' => new WC_Shipping_Legacy_International_Delivery(),
771 );
772 foreach ( $shipping_methods as $flat_rate_option_key => $shipping_method ) {
773 // Stop this running more than once if routine is repeated.
774 if ( version_compare( $shipping_method->get_option( 'version', 0 ), '2.4.0', '<' ) ) {
775 $shipping_classes = WC()->shipping()->get_shipping_classes();
776 $has_classes = count( $shipping_classes ) > 0;
777 $cost_key = $has_classes ? 'no_class_cost' : 'cost';
778 $min_fee = $shipping_method->get_option( 'minimum_fee' );
779 $math_cost_strings = array(
780 'cost' => array(),
781 'no_class_cost' => array(),
782 );
783
784 $math_cost_strings[ $cost_key ][] = $shipping_method->get_option( 'cost' );
785 $fee = $shipping_method->get_option( 'fee' );
786
787 if ( $fee ) {
788 $math_cost_strings[ $cost_key ][] = strstr( $fee, '%' ) ? '[fee percent="' . str_replace( '%', '', $fee ) . '" min="' . esc_attr( $min_fee ) . '"]' : $fee;
789 }
790
791 foreach ( $shipping_classes as $shipping_class ) {
792 $rate_key = 'class_cost_' . $shipping_class->slug;
793 $math_cost_strings[ $rate_key ] = $math_cost_strings['no_class_cost'];
794 }
795
796 $flat_rates = array_filter( (array) get_option( $flat_rate_option_key, array() ) );
797
798 if ( $flat_rates ) {
799 foreach ( $flat_rates as $shipping_class => $rate ) {
800 $rate_key = 'class_cost_' . $shipping_class;
801 if ( $rate['cost'] || $rate['fee'] ) {
802 $math_cost_strings[ $rate_key ][] = $rate['cost'];
803 $math_cost_strings[ $rate_key ][] = strstr( $rate['fee'], '%' ) ? '[fee percent="' . str_replace( '%', '', $rate['fee'] ) . '" min="' . esc_attr( $min_fee ) . '"]' : $rate['fee'];
804 }
805 }
806 }
807
808 if ( 'item' === $shipping_method->type ) {
809 foreach ( $math_cost_strings as $key => $math_cost_string ) {
810 $math_cost_strings[ $key ] = array_filter( array_map( 'trim', $math_cost_strings[ $key ] ) );
811 if ( ! empty( $math_cost_strings[ $key ] ) ) {
812 $last_key = max( 0, count( $math_cost_strings[ $key ] ) - 1 );
813 $math_cost_strings[ $key ][0] = '( ' . $math_cost_strings[ $key ][0];
814 $math_cost_strings[ $key ][ $last_key ] .= ' ) * [qty]';
815 }
816 }
817 }
818
819 $math_cost_strings['cost'][] = $shipping_method->get_option( 'cost_per_order' );
820
821 // Save settings.
822 foreach ( $math_cost_strings as $option_id => $math_cost_string ) {
823 $shipping_method->settings[ $option_id ] = implode( ' + ', array_filter( $math_cost_string ) );
824 }
825
826 $shipping_method->settings['version'] = '2.4.0';
827 $shipping_method->settings['type'] = 'item' === $shipping_method->settings['type'] ? 'class' : $shipping_method->settings['type'];
828
829 update_option( $shipping_method->plugin_id . $shipping_method->id . '_settings', $shipping_method->settings );
830 }
831 }
832 }
833
834 /**
835 * Update API keys for 2.4
836 *
837 * @return void
838 */
839 function wc_update_240_api_keys() {
840 global $wpdb;
841 /**
842 * Update the old user API keys to the new Apps keys.
843 */
844 $api_users = $wpdb->get_results( "SELECT user_id FROM $wpdb->usermeta WHERE meta_key = 'woocommerce_api_consumer_key'" );
845 $apps_keys = array();
846
847 // Get user data.
848 foreach ( $api_users as $_user ) {
849 $user = get_userdata( $_user->user_id );
850 $apps_keys[] = array(
851 'user_id' => $user->ID,
852 'permissions' => $user->woocommerce_api_key_permissions,
853 'consumer_key' => wc_api_hash( $user->woocommerce_api_consumer_key ),
854 'consumer_secret' => $user->woocommerce_api_consumer_secret,
855 'truncated_key' => substr( $user->woocommerce_api_consumer_secret, -7 ),
856 );
857 }
858
859 if ( ! empty( $apps_keys ) ) {
860 // Create new apps.
861 foreach ( $apps_keys as $app ) {
862 $wpdb->insert(
863 $wpdb->prefix . 'woocommerce_api_keys',
864 $app,
865 array(
866 '%d',
867 '%s',
868 '%s',
869 '%s',
870 '%s',
871 )
872 );
873 }
874
875 // Delete old user keys from usermeta.
876 foreach ( $api_users as $_user ) {
877 $user_id = intval( $_user->user_id );
878 delete_user_meta( $user_id, 'woocommerce_api_consumer_key' );
879 delete_user_meta( $user_id, 'woocommerce_api_consumer_secret' );
880 delete_user_meta( $user_id, 'woocommerce_api_key_permissions' );
881 }
882 }
883 }
884
885 /**
886 * Update webhooks for 2.4
887 *
888 * @return void
889 */
890 function wc_update_240_webhooks() {
891 // phpcs:disable WordPress.DB.SlowDBQuery
892
893 /**
894 * Webhooks.
895 * Make sure order.update webhooks get the woocommerce_order_edit_status hook.
896 */
897 $order_update_webhooks = get_posts(
898 array(
899 'posts_per_page' => -1,
900 'post_type' => 'shop_webhook',
901 'meta_key' => '_topic',
902 'meta_value' => 'order.updated',
903 )
904 );
905 foreach ( $order_update_webhooks as $order_update_webhook ) {
906 $webhook = new WC_Webhook( $order_update_webhook->ID );
907 $webhook->set_topic( 'order.updated' );
908 }
909
910 // phpcs:enable WordPress.DB.SlowDBQuery
911 }
912
913 /**
914 * Update refunds for 2.4
915 *
916 * @return void
917 */
918 function wc_update_240_refunds() {
919 global $wpdb;
920 /**
921 * Refunds for full refunded orders.
922 * Update fully refunded orders to ensure they have a refund line item so reports add up.
923 */
924 $refunded_orders = get_posts(
925 array(
926 'posts_per_page' => -1,
927 'post_type' => 'shop_order',
928 'post_status' => array( 'wc-refunded' ),
929 )
930 );
931
932 // Ensure emails are disabled during this update routine.
933 remove_all_actions( 'woocommerce_order_status_refunded_notification' );
934 remove_all_actions( 'woocommerce_order_partially_refunded_notification' );
935 remove_action( 'woocommerce_order_status_refunded', array( 'WC_Emails', 'send_transactional_email' ) );
936 remove_action( 'woocommerce_order_partially_refunded', array( 'WC_Emails', 'send_transactional_email' ) );
937
938 foreach ( $refunded_orders as $refunded_order ) {
939 $order_total = get_post_meta( $refunded_order->ID, '_order_total', true );
940 $refunded_total = $wpdb->get_var(
941 $wpdb->prepare(
942 "SELECT SUM( postmeta.meta_value )
943 FROM $wpdb->postmeta AS postmeta
944 INNER JOIN $wpdb->posts AS posts ON ( posts.post_type = 'shop_order_refund' AND posts.post_parent = %d )
945 WHERE postmeta.meta_key = '_refund_amount'
946 AND postmeta.post_id = posts.ID",
947 $refunded_order->ID
948 )
949 );
950
951 if ( $order_total > $refunded_total ) {
952 wc_create_refund(
953 array(
954 'amount' => $order_total - $refunded_total,
955 'reason' => __( 'Order fully refunded', 'woocommerce' ),
956 'order_id' => $refunded_order->ID,
957 'line_items' => array(),
958 'date' => $refunded_order->post_modified,
959 )
960 );
961 }
962 }
963
964 wc_delete_shop_order_transients();
965 }
966
967 /**
968 * Update DB version for 2.4
969 *
970 * @return void
971 */
972 function wc_update_240_db_version() {
973 WC_Install::update_db_version( '2.4.0' );
974 }
975
976 /**
977 * Update variations for 2.4.1
978 *
979 * @return void
980 */
981 function wc_update_241_variations() {
982 global $wpdb;
983
984 // Select variations that don't have any _stock_status implemented on WooCommerce 2.2.
985 $update_variations = $wpdb->get_results(
986 "SELECT DISTINCT posts.ID AS variation_id, posts.post_parent AS variation_parent
987 FROM {$wpdb->posts} as posts
988 LEFT OUTER JOIN {$wpdb->postmeta} AS postmeta ON posts.ID = postmeta.post_id AND postmeta.meta_key = '_stock_status'
989 WHERE posts.post_type = 'product_variation'
990 AND postmeta.meta_value IS NULL"
991 );
992
993 foreach ( $update_variations as $variation ) {
994 // Get the parent _stock_status.
995 $parent_stock_status = get_post_meta( $variation->variation_parent, '_stock_status', true );
996
997 // Set the _stock_status.
998 add_post_meta( $variation->variation_id, '_stock_status', $parent_stock_status ? $parent_stock_status : 'instock', true );
999
1000 // Delete old product children array.
1001 delete_transient( 'wc_product_children_' . $variation->variation_parent );
1002 }
1003
1004 // Invalidate old transients such as wc_var_price.
1005 WC_Cache_Helper::get_transient_version( 'product', true );
1006 }
1007
1008 /**
1009 * Update DB version for 2.4.1
1010 *
1011 * @return void
1012 */
1013 function wc_update_241_db_version() {
1014 WC_Install::update_db_version( '2.4.1' );
1015 }
1016
1017 /**
1018 * Update currency settings for 2.5
1019 *
1020 * @return void
1021 */
1022 function wc_update_250_currency() {
1023 global $wpdb;
1024 // Fix currency settings for LAK currency.
1025 $current_currency = get_option( 'woocommerce_currency' );
1026
1027 if ( 'KIP' === $current_currency ) {
1028 update_option( 'woocommerce_currency', 'LAK' );
1029 }
1030
1031 // phpcs:disable WordPress.DB.SlowDBQuery
1032
1033 // Update LAK currency code.
1034 $wpdb->update(
1035 $wpdb->postmeta,
1036 array(
1037 'meta_value' => 'LAK',
1038 ),
1039 array(
1040 'meta_key' => '_order_currency',
1041 'meta_value' => 'KIP',
1042 )
1043 );
1044
1045 // phpcs:enable WordPress.DB.SlowDBQuery
1046 }
1047
1048 /**
1049 * Update DB version for 2.5
1050 *
1051 * @return void
1052 */
1053 function wc_update_250_db_version() {
1054 WC_Install::update_db_version( '2.5.0' );
1055 }
1056
1057 /**
1058 * Update ship to countries options for 2.6
1059 *
1060 * @return void
1061 */
1062 function wc_update_260_options() {
1063 // woocommerce_calc_shipping option has been removed in 2.6.
1064 if ( 'no' === get_option( 'woocommerce_calc_shipping' ) ) {
1065 update_option( 'woocommerce_ship_to_countries', 'disabled' );
1066 }
1067
1068 WC_Admin_Notices::add_notice( 'legacy_shipping' );
1069 }
1070
1071 /**
1072 * Update term meta for 2.6
1073 *
1074 * @return void
1075 */
1076 function wc_update_260_termmeta() {
1077 global $wpdb;
1078 /**
1079 * Migrate term meta to WordPress tables.
1080 */
1081 if ( get_option( 'db_version' ) >= 34370 && $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->prefix}woocommerce_termmeta';" ) ) {
1082 if ( $wpdb->query( "INSERT INTO {$wpdb->termmeta} ( term_id, meta_key, meta_value ) SELECT woocommerce_term_id, meta_key, meta_value FROM {$wpdb->prefix}woocommerce_termmeta;" ) ) {
1083 $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}woocommerce_termmeta" );
1084 wp_cache_flush();
1085 }
1086 }
1087 }
1088
1089 /**
1090 * Update zones for 2.6
1091 *
1092 * @return void
1093 */
1094 function wc_update_260_zones() {
1095 global $wpdb;
1096 /**
1097 * Old (table rate) shipping zones to new core shipping zones migration.
1098 * zone_enabled and zone_type are no longer used, but it's safe to leave them be.
1099 */
1100 if ( $wpdb->get_var( "SHOW COLUMNS FROM `{$wpdb->prefix}woocommerce_shipping_zones` LIKE 'zone_enabled';" ) ) {
1101 $wpdb->query( "ALTER TABLE {$wpdb->prefix}woocommerce_shipping_zones CHANGE `zone_type` `zone_type` VARCHAR(40) NOT NULL DEFAULT '';" );
1102 $wpdb->query( "ALTER TABLE {$wpdb->prefix}woocommerce_shipping_zones CHANGE `zone_enabled` `zone_enabled` INT(1) NOT NULL DEFAULT 1;" );
1103 }
1104 }
1105
1106 /**
1107 * Update zone methods for 2.6
1108 *
1109 * @return void
1110 */
1111 function wc_update_260_zone_methods() {
1112 global $wpdb;
1113
1114 /**
1115 * Shipping zones in WC 2.6.0 use a table named woocommerce_shipping_zone_methods.
1116 * Migrate the old data out of woocommerce_shipping_zone_shipping_methods into the new table and port over any known options (used by table rates and flat rate boxes).
1117 */
1118 if ( $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->prefix}woocommerce_shipping_zone_shipping_methods';" ) ) {
1119 $old_methods = $wpdb->get_results( "SELECT zone_id, shipping_method_type, shipping_method_order, shipping_method_id FROM {$wpdb->prefix}woocommerce_shipping_zone_shipping_methods;" );
1120
1121 if ( $old_methods ) {
1122 $max_new_id = $wpdb->get_var( "SELECT MAX(instance_id) FROM {$wpdb->prefix}woocommerce_shipping_zone_methods" );
1123 $max_old_id = $wpdb->get_var( "SELECT MAX(shipping_method_id) FROM {$wpdb->prefix}woocommerce_shipping_zone_shipping_methods" );
1124
1125 // Avoid ID conflicts.
1126 $wpdb->query( $wpdb->prepare( "ALTER TABLE {$wpdb->prefix}woocommerce_shipping_zone_methods AUTO_INCREMENT = %d;", max( $max_new_id, $max_old_id ) + 1 ) );
1127
1128 // Store changes.
1129 $changes = array();
1130
1131 // Move data.
1132 foreach ( $old_methods as $old_method ) {
1133 $wpdb->insert(
1134 $wpdb->prefix . 'woocommerce_shipping_zone_methods',
1135 array(
1136 'zone_id' => $old_method->zone_id,
1137 'method_id' => $old_method->shipping_method_type,
1138 'method_order' => $old_method->shipping_method_order,
1139 )
1140 );
1141
1142 $new_instance_id = $wpdb->insert_id;
1143
1144 // Move main settings.
1145 $older_settings_key = 'woocommerce_' . $old_method->shipping_method_type . '-' . $old_method->shipping_method_id . '_settings';
1146 $old_settings_key = 'woocommerce_' . $old_method->shipping_method_type . '_' . $old_method->shipping_method_id . '_settings';
1147 add_option( 'woocommerce_' . $old_method->shipping_method_type . '_' . $new_instance_id . '_settings', get_option( $old_settings_key, get_option( $older_settings_key ) ) );
1148
1149 // Handling for table rate and flat rate box shipping.
1150 if ( 'table_rate' === $old_method->shipping_method_type ) {
1151 // Move priority settings.
1152 add_option( 'woocommerce_table_rate_default_priority_' . $new_instance_id, get_option( 'woocommerce_table_rate_default_priority_' . $old_method->shipping_method_id ) );
1153 add_option( 'woocommerce_table_rate_priorities_' . $new_instance_id, get_option( 'woocommerce_table_rate_priorities_' . $old_method->shipping_method_id ) );
1154
1155 // Move rates.
1156 $wpdb->update(
1157 $wpdb->prefix . 'woocommerce_shipping_table_rates',
1158 array(
1159 'shipping_method_id' => $new_instance_id,
1160 ),
1161 array(
1162 'shipping_method_id' => $old_method->shipping_method_id,
1163 )
1164 );
1165 } elseif ( 'flat_rate_boxes' === $old_method->shipping_method_type ) {
1166 $wpdb->update(
1167 $wpdb->prefix . 'woocommerce_shipping_flat_rate_boxes',
1168 array(
1169 'shipping_method_id' => $new_instance_id,
1170 ),
1171 array(
1172 'shipping_method_id' => $old_method->shipping_method_id,
1173 )
1174 );
1175 }
1176
1177 $changes[ $old_method->shipping_method_id ] = $new_instance_id;
1178 }
1179
1180 // $changes contains keys (old method ids) and values (new instance ids) if extra processing is needed in plugins.
1181 // Store this to an option so extensions can pick it up later, then fire an action.
1182 update_option( 'woocommerce_updated_instance_ids', $changes );
1183 do_action( 'woocommerce_updated_instance_ids', $changes );
1184 }
1185 }
1186
1187 // Change ranges used to ...
1188 $wpdb->query( "UPDATE {$wpdb->prefix}woocommerce_shipping_zone_locations SET location_code = REPLACE( location_code, '-', '...' );" );
1189 }
1190
1191 /**
1192 * Update refunds for 2.6
1193 *
1194 * @return void
1195 */
1196 function wc_update_260_refunds() {
1197 global $wpdb;
1198 /**
1199 * Refund item qty should be negative.
1200 */
1201 $wpdb->query(
1202 "UPDATE {$wpdb->prefix}woocommerce_order_itemmeta as item_meta
1203 LEFT JOIN {$wpdb->prefix}woocommerce_order_items as items ON item_meta.order_item_id = items.order_item_id
1204 LEFT JOIN {$wpdb->posts} as posts ON items.order_id = posts.ID
1205 SET item_meta.meta_value = item_meta.meta_value * -1
1206 WHERE item_meta.meta_value > 0 AND item_meta.meta_key = '_qty' AND posts.post_type = 'shop_order_refund'"
1207 );
1208 }
1209
1210 /**
1211 * Update DB version for 2.6
1212 *
1213 * @return void
1214 */
1215 function wc_update_260_db_version() {
1216 WC_Install::update_db_version( '2.6.0' );
1217 }
1218
1219 /**
1220 * Update webhooks for 3.0
1221 *
1222 * @return void
1223 */
1224 function wc_update_300_webhooks() {
1225 // phpcs:disable WordPress.DB.SlowDBQuery
1226
1227 /**
1228 * Make sure product.update webhooks get the woocommerce_product_quick_edit_save
1229 * and woocommerce_product_bulk_edit_save hooks.
1230 */
1231 $product_update_webhooks = get_posts(
1232 array(
1233 'posts_per_page' => -1,
1234 'post_type' => 'shop_webhook',
1235 'meta_key' => '_topic',
1236 'meta_value' => 'product.updated',
1237 )
1238 );
1239 foreach ( $product_update_webhooks as $product_update_webhook ) {
1240 $webhook = new WC_Webhook( $product_update_webhook->ID );
1241 $webhook->set_topic( 'product.updated' );
1242 }
1243
1244 // phpcs:enable WordPress.DB.SlowDBQuery
1245 }
1246
1247 /**
1248 * Add an index to the field comment_type to improve the response time of the query
1249 * used by WC_Comments::wp_count_comments() to get the number of comments by type.
1250 */
1251 function wc_update_300_comment_type_index() {
1252 global $wpdb;
1253
1254 $index_exists = $wpdb->get_row( "SHOW INDEX FROM {$wpdb->comments} WHERE column_name = 'comment_type' and key_name = 'woo_idx_comment_type'" );
1255
1256 if ( is_null( $index_exists ) ) {
1257 // Add an index to the field comment_type to improve the response time of the query
1258 // used by WC_Comments::wp_count_comments() to get the number of comments by type.
1259 $wpdb->query( "ALTER TABLE {$wpdb->comments} ADD INDEX woo_idx_comment_type (comment_type)" );
1260 }
1261 }
1262
1263 /**
1264 * Update grouped products for 3.0
1265 *
1266 * @return void
1267 */
1268 function wc_update_300_grouped_products() {
1269 global $wpdb;
1270 $parents = $wpdb->get_col( "SELECT DISTINCT( post_parent ) FROM {$wpdb->posts} WHERE post_parent > 0 AND post_type = 'product';" );
1271 foreach ( $parents as $parent_id ) {
1272 $parent = wc_get_product( $parent_id );
1273 if ( $parent && $parent->is_type( 'grouped' ) ) {
1274 $children_ids = get_posts(
1275 array(
1276 'post_parent' => $parent_id,
1277 'posts_per_page' => -1,
1278 'post_type' => 'product',
1279 'fields' => 'ids',
1280 )
1281 );
1282 update_post_meta( $parent_id, '_children', $children_ids );
1283
1284 // Update children to remove the parent.
1285 $wpdb->update(
1286 $wpdb->posts,
1287 array(
1288 'post_parent' => 0,
1289 ),
1290 array(
1291 'post_parent' => $parent_id,
1292 )
1293 );
1294 }
1295 }
1296 }
1297
1298 /**
1299 * Update shipping tax classes for 3.0
1300 *
1301 * @return void
1302 */
1303 function wc_update_300_settings() {
1304 $woocommerce_shipping_tax_class = get_option( 'woocommerce_shipping_tax_class' );
1305 if ( '' === $woocommerce_shipping_tax_class ) {
1306 update_option( 'woocommerce_shipping_tax_class', 'inherit' );
1307 } elseif ( 'standard' === $woocommerce_shipping_tax_class ) {
1308 update_option( 'woocommerce_shipping_tax_class', '' );
1309 }
1310 }
1311
1312 /**
1313 * Convert meta values into term for product visibility.
1314 */
1315 function wc_update_300_product_visibility() {
1316 global $wpdb;
1317
1318 WC_Install::create_terms();
1319
1320 $featured_term = get_term_by( 'name', 'featured', 'product_visibility' );
1321
1322 if ( $featured_term ) {
1323 $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO {$wpdb->term_relationships} SELECT post_id, %d, 0 FROM {$wpdb->postmeta} WHERE meta_key = '_featured' AND meta_value = 'yes';", $featured_term->term_taxonomy_id ) );
1324 }
1325
1326 $exclude_search_term = get_term_by( 'name', 'exclude-from-search', 'product_visibility' );
1327
1328 if ( $exclude_search_term ) {
1329 $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO {$wpdb->term_relationships} SELECT post_id, %d, 0 FROM {$wpdb->postmeta} WHERE meta_key = '_visibility' AND meta_value IN ('hidden', 'catalog');", $exclude_search_term->term_taxonomy_id ) );
1330 }
1331
1332 $exclude_catalog_term = get_term_by( 'name', 'exclude-from-catalog', 'product_visibility' );
1333
1334 if ( $exclude_catalog_term ) {
1335 $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO {$wpdb->term_relationships} SELECT post_id, %d, 0 FROM {$wpdb->postmeta} WHERE meta_key = '_visibility' AND meta_value IN ('hidden', 'search');", $exclude_catalog_term->term_taxonomy_id ) );
1336 }
1337
1338 $outofstock_term = get_term_by( 'name', 'outofstock', 'product_visibility' );
1339
1340 if ( $outofstock_term ) {
1341 $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO {$wpdb->term_relationships} SELECT post_id, %d, 0 FROM {$wpdb->postmeta} WHERE meta_key = '_stock_status' AND meta_value = 'outofstock';", $outofstock_term->term_taxonomy_id ) );
1342 }
1343
1344 $rating_term = get_term_by( 'name', 'rated-1', 'product_visibility' );
1345
1346 if ( $rating_term ) {
1347 $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO {$wpdb->term_relationships} SELECT post_id, %d, 0 FROM {$wpdb->postmeta} WHERE meta_key = '_wc_average_rating' AND ROUND( meta_value ) = 1;", $rating_term->term_taxonomy_id ) );
1348 }
1349
1350 $rating_term = get_term_by( 'name', 'rated-2', 'product_visibility' );
1351
1352 if ( $rating_term ) {
1353 $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO {$wpdb->term_relationships} SELECT post_id, %d, 0 FROM {$wpdb->postmeta} WHERE meta_key = '_wc_average_rating' AND ROUND( meta_value ) = 2;", $rating_term->term_taxonomy_id ) );
1354 }
1355
1356 $rating_term = get_term_by( 'name', 'rated-3', 'product_visibility' );
1357
1358 if ( $rating_term ) {
1359 $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO {$wpdb->term_relationships} SELECT post_id, %d, 0 FROM {$wpdb->postmeta} WHERE meta_key = '_wc_average_rating' AND ROUND( meta_value ) = 3;", $rating_term->term_taxonomy_id ) );
1360 }
1361
1362 $rating_term = get_term_by( 'name', 'rated-4', 'product_visibility' );
1363
1364 if ( $rating_term ) {
1365 $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO {$wpdb->term_relationships} SELECT post_id, %d, 0 FROM {$wpdb->postmeta} WHERE meta_key = '_wc_average_rating' AND ROUND( meta_value ) = 4;", $rating_term->term_taxonomy_id ) );
1366 }
1367
1368 $rating_term = get_term_by( 'name', 'rated-5', 'product_visibility' );
1369
1370 if ( $rating_term ) {
1371 $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO {$wpdb->term_relationships} SELECT post_id, %d, 0 FROM {$wpdb->postmeta} WHERE meta_key = '_wc_average_rating' AND ROUND( meta_value ) = 5;", $rating_term->term_taxonomy_id ) );
1372 }
1373 }
1374
1375 /**
1376 * Update DB Version.
1377 */
1378 function wc_update_300_db_version() {
1379 WC_Install::update_db_version( '3.0.0' );
1380 }
1381
1382 /**
1383 * Add an index to the downloadable product permissions table to improve performance of update_user_by_order_id.
1384 */
1385 function wc_update_310_downloadable_products() {
1386 global $wpdb;
1387
1388 $index_exists = $wpdb->get_row( "SHOW INDEX FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE column_name = 'order_id' and key_name = 'order_id'" );
1389
1390 if ( is_null( $index_exists ) ) {
1391 $wpdb->query( "ALTER TABLE {$wpdb->prefix}woocommerce_downloadable_product_permissions ADD INDEX order_id (order_id)" );
1392 }
1393 }
1394
1395 /**
1396 * Find old order notes and ensure they have the correct type for exclusion.
1397 */
1398 function wc_update_310_old_comments() {
1399 global $wpdb;
1400
1401 $wpdb->query( "UPDATE $wpdb->comments comments LEFT JOIN $wpdb->posts as posts ON comments.comment_post_ID = posts.ID SET comment_type = 'order_note' WHERE posts.post_type = 'shop_order' AND comment_type = '';" );
1402 }
1403
1404 /**
1405 * Update DB Version.
1406 */
1407 function wc_update_310_db_version() {
1408 WC_Install::update_db_version( '3.1.0' );
1409 }
1410
1411 /**
1412 * Update shop_manager capabilities.
1413 */
1414 function wc_update_312_shop_manager_capabilities() {
1415 $role = get_role( 'shop_manager' );
1416 $role->remove_cap( 'unfiltered_html' );
1417 }
1418
1419 /**
1420 * Update DB Version.
1421 */
1422 function wc_update_312_db_version() {
1423 WC_Install::update_db_version( '3.1.2' );
1424 }
1425
1426 /**
1427 * Update state codes for Mexico.
1428 */
1429 function wc_update_320_mexican_states() {
1430 global $wpdb;
1431
1432 $mx_states = array(
1433 'Distrito Federal' => 'CMX',
1434 'Jalisco' => 'JAL',
1435 'Nuevo Leon' => 'NLE',
1436 'Aguascalientes' => 'AGS',
1437 'Baja California' => 'BCN',
1438 'Baja California Sur' => 'BCS',
1439 'Campeche' => 'CAM',
1440 'Chiapas' => 'CHP',
1441 'Chihuahua' => 'CHH',
1442 'Coahuila' => 'COA',
1443 'Colima' => 'COL',
1444 'Durango' => 'DGO',
1445 'Guanajuato' => 'GTO',
1446 'Guerrero' => 'GRO',
1447 'Hidalgo' => 'HGO',
1448 'Estado de Mexico' => 'MEX',
1449 'Michoacan' => 'MIC',
1450 'Morelos' => 'MOR',
1451 'Nayarit' => 'NAY',
1452 'Oaxaca' => 'OAX',
1453 'Puebla' => 'PUE',
1454 'Queretaro' => 'QRO',
1455 'Quintana Roo' => 'ROO',
1456 'San Luis Potosi' => 'SLP',
1457 'Sinaloa' => 'SIN',
1458 'Sonora' => 'SON',
1459 'Tabasco' => 'TAB',
1460 'Tamaulipas' => 'TMP',
1461 'Tlaxcala' => 'TLA',
1462 'Veracruz' => 'VER',
1463 'Yucatan' => 'YUC',
1464 'Zacatecas' => 'ZAC',
1465 );
1466
1467 foreach ( $mx_states as $old => $new ) {
1468 $wpdb->query(
1469 $wpdb->prepare(
1470 "UPDATE $wpdb->postmeta
1471 SET meta_value = %s
1472 WHERE meta_key IN ( '_billing_state', '_shipping_state' )
1473 AND meta_value = %s",
1474 $new,
1475 $old
1476 )
1477 );
1478 $wpdb->update(
1479 "{$wpdb->prefix}woocommerce_shipping_zone_locations",
1480 array(
1481 'location_code' => 'MX:' . $new,
1482 ),
1483 array(
1484 'location_code' => 'MX:' . $old,
1485 )
1486 );
1487 $wpdb->update(
1488 "{$wpdb->prefix}woocommerce_tax_rates",
1489 array(
1490 'tax_rate_state' => strtoupper( $new ),
1491 ),
1492 array(
1493 'tax_rate_state' => strtoupper( $old ),
1494 )
1495 );
1496 }
1497 }
1498
1499 /**
1500 * Update DB Version.
1501 */
1502 function wc_update_320_db_version() {
1503 WC_Install::update_db_version( '3.2.0' );
1504 }
1505
1506 /**
1507 * Update image settings to use new aspect ratios and widths.
1508 */
1509 function wc_update_330_image_options() {
1510 $old_thumbnail_size = get_option( 'shop_catalog_image_size', array() );
1511 $old_single_size = get_option( 'shop_single_image_size', array() );
1512
1513 if ( ! empty( $old_thumbnail_size['width'] ) ) {
1514 $width = absint( $old_thumbnail_size['width'] );
1515 $height = absint( $old_thumbnail_size['height'] );
1516 $hard_crop = ! empty( $old_thumbnail_size['crop'] );
1517
1518 if ( ! $width ) {
1519 $width = 300;
1520 }
1521
1522 if ( ! $height ) {
1523 $height = $width;
1524 }
1525
1526 update_option( 'woocommerce_thumbnail_image_width', $width );
1527
1528 // Calculate cropping mode from old image options.
1529 if ( ! $hard_crop ) {
1530 update_option( 'woocommerce_thumbnail_cropping', 'uncropped' );
1531 } elseif ( $width === $height ) {
1532 update_option( 'woocommerce_thumbnail_cropping', '1:1' );
1533 } else {
1534 $ratio = $width / $height;
1535 $fraction = wc_decimal_to_fraction( $ratio );
1536
1537 if ( $fraction ) {
1538 update_option( 'woocommerce_thumbnail_cropping', 'custom' );
1539 update_option( 'woocommerce_thumbnail_cropping_custom_width', $fraction[0] );
1540 update_option( 'woocommerce_thumbnail_cropping_custom_height', $fraction[1] );
1541 }
1542 }
1543 }
1544
1545 // Single is uncropped.
1546 if ( ! empty( $old_single_size['width'] ) ) {
1547 update_option( 'woocommerce_single_image_width', absint( $old_single_size['width'] ) );
1548 }
1549 }
1550
1551 /**
1552 * Migrate webhooks from post type to CRUD.
1553 */
1554 function wc_update_330_webhooks() {
1555 register_post_type( 'shop_webhook' );
1556
1557 // Map statuses from post_type to Webhooks CRUD.
1558 $statuses = array(
1559 'publish' => 'active',
1560 'draft' => 'paused',
1561 'pending' => 'disabled',
1562 );
1563
1564 $posts = get_posts(
1565 array(
1566 'posts_per_page' => -1,
1567 'post_type' => 'shop_webhook',
1568 'post_status' => 'any',
1569 )
1570 );
1571
1572 foreach ( $posts as $post ) {
1573 $webhook = new WC_Webhook();
1574 $webhook->set_name( $post->post_title );
1575 $webhook->set_status( isset( $statuses[ $post->post_status ] ) ? $statuses[ $post->post_status ] : 'disabled' );
1576 $webhook->set_delivery_url( get_post_meta( $post->ID, '_delivery_url', true ) );
1577 $webhook->set_secret( get_post_meta( $post->ID, '_secret', true ) );
1578 $webhook->set_topic( get_post_meta( $post->ID, '_topic', true ) );
1579 $webhook->set_api_version( get_post_meta( $post->ID, '_api_version', true ) );
1580 $webhook->set_user_id( $post->post_author );
1581 $webhook->set_pending_delivery( false );
1582 $webhook->save();
1583
1584 wp_delete_post( $post->ID, true );
1585 }
1586
1587 unregister_post_type( 'shop_webhook' );
1588 }
1589
1590 /**
1591 * Assign default cat to all products with no cats.
1592 */
1593 function wc_update_330_set_default_product_cat() {
1594 /*
1595 * When a product category is deleted, we need to check
1596 * if the product has no categories assigned. Then assign
1597 * it a default category.
1598 */
1599 wc_get_container()->get( AssignDefaultCategory::class )->maybe_assign_default_product_cat();
1600 }
1601
1602 /**
1603 * Update product stock status to use the new onbackorder status.
1604 */
1605 function wc_update_330_product_stock_status() {
1606 global $wpdb;
1607
1608 if ( 'yes' !== get_option( 'woocommerce_manage_stock' ) ) {
1609 return;
1610 }
1611
1612 $min_stock_amount = (int) get_option( 'woocommerce_notify_no_stock_amount', 0 );
1613
1614 // Get all products that have stock management enabled, stock less than or equal to min stock amount, and backorders enabled.
1615 $post_ids = $wpdb->get_col(
1616 $wpdb->prepare(
1617 "SELECT t1.post_id FROM $wpdb->postmeta t1
1618 INNER JOIN $wpdb->postmeta t2
1619 ON t1.post_id = t2.post_id
1620 AND t1.meta_key = '_manage_stock' AND t1.meta_value = 'yes'
1621 AND t2.meta_key = '_stock' AND t2.meta_value <= %d
1622 INNER JOIN $wpdb->postmeta t3
1623 ON t2.post_id = t3.post_id
1624 AND t3.meta_key = '_backorders' AND ( t3.meta_value = 'yes' OR t3.meta_value = 'notify' )",
1625 $min_stock_amount
1626 )
1627 );
1628
1629 if ( empty( $post_ids ) ) {
1630 return;
1631 }
1632
1633 $post_ids = array_map( 'absint', $post_ids );
1634
1635 // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
1636 // Set the status to onbackorder for those products.
1637 $wpdb->query(
1638 "UPDATE $wpdb->postmeta
1639 SET meta_value = 'onbackorder'
1640 WHERE meta_key = '_stock_status' AND post_id IN ( " . implode( ',', $post_ids ) . ' )'
1641 );
1642 // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
1643 }
1644
1645 /**
1646 * Clear addons page transients
1647 */
1648 function wc_update_330_clear_transients() {
1649 delete_transient( 'wc_addons_sections' );
1650 delete_transient( 'wc_addons_featured' );
1651 }
1652
1653 /**
1654 * Set PayPal's sandbox credentials.
1655 */
1656 function wc_update_330_set_paypal_sandbox_credentials() {
1657
1658 $paypal_settings = get_option( 'woocommerce_paypal_settings' );
1659
1660 if ( isset( $paypal_settings['testmode'] ) && 'yes' === $paypal_settings['testmode'] ) {
1661 foreach ( array( 'api_username', 'api_password', 'api_signature' ) as $credential ) {
1662 if ( ! empty( $paypal_settings[ $credential ] ) ) {
1663 $paypal_settings[ 'sandbox_' . $credential ] = $paypal_settings[ $credential ];
1664 }
1665 }
1666
1667 update_option( 'woocommerce_paypal_settings', $paypal_settings );
1668 }
1669 }
1670
1671 /**
1672 * Update DB Version.
1673 */
1674 function wc_update_330_db_version() {
1675 WC_Install::update_db_version( '3.3.0' );
1676 }
1677
1678 /**
1679 * Update state codes for Ireland and BD.
1680 */
1681 function wc_update_340_states() {
1682 $country_states = array(
1683 'IE' => array(
1684 'CK' => 'CO',
1685 'DN' => 'D',
1686 'GY' => 'G',
1687 'TY' => 'TA',
1688 ),
1689 'BD' => array(
1690 'BAG' => 'BD-05',
1691 'BAN' => 'BD-01',
1692 'BAR' => 'BD-02',
1693 'BARI' => 'BD-06',
1694 'BHO' => 'BD-07',
1695 'BOG' => 'BD-03',
1696 'BRA' => 'BD-04',
1697 'CHA' => 'BD-09',
1698 'CHI' => 'BD-10',
1699 'CHU' => 'BD-12',
1700 'COX' => 'BD-11',
1701 'COM' => 'BD-08',
1702 'DHA' => 'BD-13',
1703 'DIN' => 'BD-14',
1704 'FAR' => 'BD-15',
1705 'FEN' => 'BD-16',
1706 'GAI' => 'BD-19',
1707 'GAZI' => 'BD-18',
1708 'GOP' => 'BD-17',
1709 'HAB' => 'BD-20',
1710 'JAM' => 'BD-21',
1711 'JES' => 'BD-22',
1712 'JHA' => 'BD-25',
1713 'JHE' => 'BD-23',
1714 'JOY' => 'BD-24',
1715 'KHA' => 'BD-29',
1716 'KHU' => 'BD-27',
1717 'KIS' => 'BD-26',
1718 'KUR' => 'BD-28',
1719 'KUS' => 'BD-30',
1720 'LAK' => 'BD-31',
1721 'LAL' => 'BD-32',
1722 'MAD' => 'BD-36',
1723 'MAG' => 'BD-37',
1724 'MAN' => 'BD-33',
1725 'MEH' => 'BD-39',
1726 'MOU' => 'BD-38',
1727 'MUN' => 'BD-35',
1728 'MYM' => 'BD-34',
1729 'NAO' => 'BD-48',
1730 'NAR' => 'BD-43',
1731 'NARG' => 'BD-40',
1732 'NARD' => 'BD-42',
1733 'NAT' => 'BD-44',
1734 'NAW' => 'BD-45',
1735 'NET' => 'BD-41',
1736 'NIL' => 'BD-46',
1737 'NOA' => 'BD-47',
1738 'PAB' => 'BD-49',
1739 'PAN' => 'BD-52',
1740 'PAT' => 'BD-51',
1741 'PIR' => 'BD-50',
1742 'RAJB' => 'BD-53',
1743 'RAJ' => 'BD-54',
1744 'RAN' => 'BD-56',
1745 'RANP' => 'BD-55',
1746 'SAT' => 'BD-58',
1747 'SHA' => 'BD-57',
1748 'SIR' => 'BD-59',
1749 'SUN' => 'BD-61',
1750 'SYL' => 'BD-60',
1751 'TAN' => 'BD-63',
1752 'THA' => 'BD-64',
1753 ),
1754 );
1755
1756 update_option( 'woocommerce_update_340_states', $country_states );
1757 }
1758
1759 /**
1760 * Update next state in the queue.
1761 *
1762 * @return bool True to run again, false if completed.
1763 */
1764 function wc_update_340_state() {
1765 global $wpdb;
1766
1767 $country_states = array_filter( (array) get_option( 'woocommerce_update_340_states', array() ) );
1768
1769 if ( empty( $country_states ) ) {
1770 return false;
1771 }
1772
1773 foreach ( $country_states as $country => $states ) {
1774 foreach ( $states as $old => $new ) {
1775 $wpdb->query(
1776 $wpdb->prepare(
1777 "UPDATE $wpdb->postmeta
1778 SET meta_value = %s
1779 WHERE meta_key IN ( '_billing_state', '_shipping_state' )
1780 AND meta_value = %s",
1781 $new,
1782 $old
1783 )
1784 );
1785 $wpdb->update(
1786 "{$wpdb->prefix}woocommerce_shipping_zone_locations",
1787 array(
1788 'location_code' => $country . ':' . $new,
1789 ),
1790 array(
1791 'location_code' => $country . ':' . $old,
1792 )
1793 );
1794 $wpdb->update(
1795 "{$wpdb->prefix}woocommerce_tax_rates",
1796 array(
1797 'tax_rate_state' => strtoupper( $new ),
1798 ),
1799 array(
1800 'tax_rate_state' => strtoupper( $old ),
1801 )
1802 );
1803 unset( $country_states[ $country ][ $old ] );
1804
1805 if ( empty( $country_states[ $country ] ) ) {
1806 unset( $country_states[ $country ] );
1807 }
1808 break 2;
1809 }
1810 }
1811
1812 if ( ! empty( $country_states ) ) {
1813 return update_option( 'woocommerce_update_340_states', $country_states );
1814 }
1815
1816 delete_option( 'woocommerce_update_340_states' );
1817
1818 return false;
1819 }
1820
1821 /**
1822 * Set last active prop for users.
1823 */
1824 function wc_update_340_last_active() {
1825 global $wpdb;
1826 // @codingStandardsIgnoreStart.
1827 $wpdb->query(
1828 $wpdb->prepare( "
1829 INSERT INTO {$wpdb->usermeta} (user_id, meta_key, meta_value)
1830 SELECT DISTINCT users.ID, 'wc_last_active', %s
1831 FROM {$wpdb->users} as users
1832 LEFT OUTER JOIN {$wpdb->usermeta} AS usermeta ON users.ID = usermeta.user_id AND usermeta.meta_key = 'wc_last_active'
1833 WHERE usermeta.meta_value IS NULL
1834 ",
1835 (string) strtotime( date( 'Y-m-d', current_time( 'timestamp', true ) ) )
1836 )
1837 );
1838 // @codingStandardsIgnoreEnd.
1839 }
1840
1841 /**
1842 * Update DB Version.
1843 */
1844 function wc_update_340_db_version() {
1845 WC_Install::update_db_version( '3.4.0' );
1846 }
1847
1848 /**
1849 * Remove duplicate foreign keys
1850 *
1851 * @return void
1852 */
1853 function wc_update_343_cleanup_foreign_keys() {
1854 global $wpdb;
1855
1856 $create_table_sql = $wpdb->get_var( "SHOW CREATE TABLE {$wpdb->prefix}wc_download_log", 1 );
1857
1858 if ( ! empty( $create_table_sql ) ) {
1859 // Extract and remove the foreign key constraints matching %wc_download_log_ib%.
1860 if ( preg_match_all( '/CONSTRAINT `([^`]*wc_download_log_ib[^`]*)` FOREIGN KEY/', $create_table_sql, $matches ) && ! empty( $matches[1] ) ) {
1861 foreach ( $matches[1] as $foreign_key_name ) {
1862 $wpdb->query( "ALTER TABLE {$wpdb->prefix}wc_download_log DROP FOREIGN KEY `{$foreign_key_name}`" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
1863 }
1864 }
1865 }
1866 }
1867
1868 /**
1869 * Update DB version.
1870 *
1871 * @return void
1872 */
1873 function wc_update_343_db_version() {
1874 WC_Install::update_db_version( '3.4.3' );
1875 }
1876
1877 /**
1878 * Recreate user roles so existing users will get the new capabilities.
1879 *
1880 * @return void
1881 */
1882 function wc_update_344_recreate_roles() {
1883 WC_Install::remove_roles();
1884 WC_Install::create_roles();
1885 }
1886
1887 /**
1888 * Update DB version.
1889 *
1890 * @return void
1891 */
1892 function wc_update_344_db_version() {
1893 WC_Install::update_db_version( '3.4.4' );
1894 }
1895
1896 /**
1897 * Set the comment type to 'review' for product reviews that don't have a comment type.
1898 */
1899 function wc_update_350_reviews_comment_type() {
1900 global $wpdb;
1901
1902 $wpdb->query(
1903 "UPDATE {$wpdb->prefix}comments JOIN {$wpdb->prefix}posts ON {$wpdb->prefix}posts.ID = {$wpdb->prefix}comments.comment_post_ID AND ( {$wpdb->prefix}posts.post_type = 'product' OR {$wpdb->prefix}posts.post_type = 'product_variation' ) SET {$wpdb->prefix}comments.comment_type = 'review' WHERE {$wpdb->prefix}comments.comment_type = ''"
1904 );
1905 }
1906
1907 /**
1908 * Update DB Version.
1909 */
1910 function wc_update_350_db_version() {
1911 WC_Install::update_db_version( '3.5.0' );
1912 }
1913
1914 /**
1915 * Drop the fk_wc_download_log_permission_id FK as we use a new one with the table and blog prefix for MS compatibility.
1916 *
1917 * @return void
1918 */
1919 function wc_update_352_drop_download_log_fk() {
1920 global $wpdb;
1921
1922 $create_table_sql = $wpdb->get_var( "SHOW CREATE TABLE {$wpdb->prefix}wc_download_log", 1 );
1923
1924 if ( ! empty( $create_table_sql ) ) {
1925 if ( strpos( $create_table_sql, 'CONSTRAINT `fk_wc_download_log_permission_id` FOREIGN KEY' ) !== false ) {
1926 $wpdb->query( "ALTER TABLE {$wpdb->prefix}wc_download_log DROP FOREIGN KEY fk_wc_download_log_permission_id" ); // phpcs:ignore WordPress.WP.PreparedSQL.NotPrepared
1927 }
1928 }
1929 }
1930
1931 /**
1932 * Remove edit_user capabilities from shop managers and use "translated" capabilities instead.
1933 * See wc_shop_manager_has_capability function.
1934 */
1935 function wc_update_354_modify_shop_manager_caps() {
1936 global $wp_roles;
1937
1938 if ( ! class_exists( 'WP_Roles' ) ) {
1939 return;
1940 }
1941
1942 if ( ! isset( $wp_roles ) ) {
1943 $wp_roles = new WP_Roles(); // @codingStandardsIgnoreLine
1944 }
1945
1946 $wp_roles->remove_cap( 'shop_manager', 'edit_users' );
1947 }
1948
1949 /**
1950 * Update DB Version.
1951 */
1952 function wc_update_354_db_version() {
1953 WC_Install::update_db_version( '3.5.4' );
1954 }
1955
1956 /**
1957 * Update product lookup tables in bulk.
1958 */
1959 function wc_update_360_product_lookup_tables() {
1960 wc_update_product_lookup_tables();
1961 }
1962
1963 /**
1964 * Renames ordering meta to be consistent across taxonomies.
1965 */
1966 function wc_update_360_term_meta() {
1967 global $wpdb;
1968
1969 $wpdb->query( "UPDATE {$wpdb->termmeta} SET meta_key = 'order' WHERE meta_key LIKE 'order_pa_%';" );
1970 }
1971
1972 /**
1973 * Add new user_order_remaining_expires to speed up user download permission fetching.
1974 *
1975 * @return void
1976 */
1977 function wc_update_360_downloadable_product_permissions_index() {
1978 global $wpdb;
1979
1980 $index_exists = $wpdb->get_row( "SHOW INDEX FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE key_name = 'user_order_remaining_expires'" );
1981
1982 if ( is_null( $index_exists ) ) {
1983 $wpdb->query( "ALTER TABLE {$wpdb->prefix}woocommerce_downloadable_product_permissions ADD INDEX user_order_remaining_expires (user_id,order_id,downloads_remaining,access_expires)" );
1984 }
1985 }
1986
1987 /**
1988 * Update DB Version.
1989 */
1990 function wc_update_360_db_version() {
1991 WC_Install::update_db_version( '3.6.0' );
1992 }
1993
1994 /**
1995 * Put tax classes into a DB table.
1996 *
1997 * @return void
1998 */
1999 function wc_update_370_tax_rate_classes() {
2000 global $wpdb;
2001
2002 $classes = array_map( 'trim', explode( "\n", get_option( 'woocommerce_tax_classes' ) ) );
2003
2004 if ( $classes ) {
2005 foreach ( $classes as $class ) {
2006 if ( empty( $class ) ) {
2007 continue;
2008 }
2009 WC_Tax::create_tax_class( $class );
2010 }
2011 }
2012 delete_option( 'woocommerce_tax_classes' );
2013 }
2014
2015 /**
2016 * Update currency settings for 3.7.0
2017 *
2018 * @return void
2019 */
2020 function wc_update_370_mro_std_currency() {
2021 global $wpdb;
2022
2023 // Fix currency settings for MRU and STN currency.
2024 $current_currency = get_option( 'woocommerce_currency' );
2025
2026 if ( 'MRO' === $current_currency ) {
2027 update_option( 'woocommerce_currency', 'MRU' );
2028 }
2029
2030 if ( 'STD' === $current_currency ) {
2031 update_option( 'woocommerce_currency', 'STN' );
2032 }
2033
2034 // Update MRU currency code.
2035 $wpdb->update(
2036 $wpdb->postmeta,
2037 array(
2038 'meta_value' => 'MRU', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
2039 ),
2040 array(
2041 'meta_key' => '_order_currency', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
2042 'meta_value' => 'MRO', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
2043 )
2044 );
2045
2046 // Update STN currency code.
2047 $wpdb->update(
2048 $wpdb->postmeta,
2049 array(
2050 'meta_value' => 'STN', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
2051 ),
2052 array(
2053 'meta_key' => '_order_currency', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
2054 'meta_value' => 'STD', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
2055 )
2056 );
2057 }
2058
2059 /**
2060 * Update DB Version.
2061 */
2062 function wc_update_370_db_version() {
2063 WC_Install::update_db_version( '3.7.0' );
2064 }
2065
2066 /**
2067 * We've moved the MaxMind database to a new location, as per the TOS' requirement that the database not
2068 * be publicly accessible.
2069 */
2070 function wc_update_390_move_maxmind_database() {
2071 // Make sure to use all of the correct filters to pull the local database path.
2072 $old_path = apply_filters( 'woocommerce_geolocation_local_database_path', WP_CONTENT_DIR . '/uploads/GeoLite2-Country.mmdb', 2 );
2073
2074 // Generate a prefix for the old file and store it in the integration as it would expect it.
2075 $prefix = wp_generate_password( 32, false );
2076 update_option( 'woocommerce_maxmind_geolocation_settings', array( 'database_prefix' => $prefix ) );
2077
2078 // Generate the new path in the same way that the integration will.
2079 $uploads_dir = wp_upload_dir();
2080 $new_path = trailingslashit( $uploads_dir['basedir'] ) . 'woocommerce_uploads/' . $prefix . '-GeoLite2-Country.mmdb';
2081 $new_path = apply_filters( 'woocommerce_geolocation_local_database_path', $new_path, 2 );
2082 $new_path = apply_filters( 'woocommerce_maxmind_geolocation_database_path', $new_path );
2083
2084 // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
2085 @rename( $old_path, $new_path );
2086 }
2087
2088 /**
2089 * So that we can best meet MaxMind's TOS, the geolocation database update cron should run once per 15 days.
2090 */
2091 function wc_update_390_change_geolocation_database_update_cron() {
2092 wp_clear_scheduled_hook( 'woocommerce_geoip_updater' );
2093 wp_schedule_event( time() + ( DAY_IN_SECONDS * 15 ), 'fifteendays', 'woocommerce_geoip_updater' );
2094 }
2095
2096 /**
2097 * Update DB version.
2098 */
2099 function wc_update_390_db_version() {
2100 WC_Install::update_db_version( '3.9.0' );
2101 }
2102
2103 /**
2104 * Increase column size
2105 */
2106 function wc_update_400_increase_size_of_column() {
2107 global $wpdb;
2108 $wpdb->query( "ALTER TABLE {$wpdb->prefix}wc_product_meta_lookup MODIFY COLUMN `min_price` decimal(19,4) NULL default NULL" );
2109 $wpdb->query( "ALTER TABLE {$wpdb->prefix}wc_product_meta_lookup MODIFY COLUMN `max_price` decimal(19,4) NULL default NULL" );
2110 }
2111
2112 /**
2113 * Reset ActionScheduler migration status. Needs AS >= 3.0 shipped with WC >= 4.0.
2114 */
2115 function wc_update_400_reset_action_scheduler_migration_status() {
2116 if (
2117 class_exists( 'ActionScheduler_DataController' ) &&
2118 method_exists( 'ActionScheduler_DataController', 'mark_migration_incomplete' )
2119 ) {
2120 \ActionScheduler_DataController::mark_migration_incomplete();
2121 }
2122 }
2123
2124 /**
2125 * Update DB version.
2126 */
2127 function wc_update_400_db_version() {
2128 WC_Install::update_db_version( '4.0.0' );
2129 }
2130
2131 /**
2132 * Register attributes as terms for variable products, in increments of 100 products.
2133 *
2134 * This migration was added to support a new mechanism to improve the filtering of
2135 * variable products by attribute (https://github.com/woocommerce/woocommerce/pull/26260),
2136 * however that mechanism was later reverted (https://github.com/woocommerce/woocommerce/pull/27625)
2137 * due to numerous issues found. Thus the migration is no longer needed.
2138 *
2139 * @return bool true if the migration needs to be run again.
2140 */
2141 function wc_update_440_insert_attribute_terms_for_variable_products() {
2142 return false;
2143 }
2144
2145 /**
2146 * Update DB version.
2147 */
2148 function wc_update_440_db_version() {
2149 WC_Install::update_db_version( '4.4.0' );
2150 }
2151
2152 /**
2153 * Update DB version to 4.5.0.
2154 */
2155 function wc_update_450_db_version() {
2156 WC_Install::update_db_version( '4.5.0' );
2157 }
2158
2159 /**
2160 * Sanitize all coupons code.
2161 *
2162 * @return bool True to run again, false if completed.
2163 */
2164 function wc_update_450_sanitize_coupons_code() {
2165 global $wpdb;
2166
2167 $coupon_id = 0;
2168 $last_coupon_id = get_option( 'woocommerce_update_450_last_coupon_id', '0' );
2169
2170 $coupons = $wpdb->get_results(
2171 $wpdb->prepare(
2172 "SELECT ID, post_title FROM $wpdb->posts WHERE ID > %d AND post_type = 'shop_coupon' LIMIT 10",
2173 $last_coupon_id
2174 ),
2175 ARRAY_A
2176 );
2177
2178 if ( empty( $coupons ) ) {
2179 delete_option( 'woocommerce_update_450_last_coupon_id' );
2180 return false;
2181 }
2182
2183 foreach ( $coupons as $key => $data ) {
2184 $coupon_id = intval( $data['ID'] );
2185 $code = trim( wp_filter_kses( $data['post_title'] ) );
2186
2187 if ( ! empty( $code ) && $data['post_title'] !== $code ) {
2188 $wpdb->update(
2189 $wpdb->posts,
2190 array(
2191 'post_title' => $code,
2192 ),
2193 array(
2194 'ID' => $coupon_id,
2195 ),
2196 array(
2197 '%s',
2198 ),
2199 array(
2200 '%d',
2201 )
2202 );
2203
2204 // Clean cache.
2205 clean_post_cache( $coupon_id );
2206 wp_cache_delete( WC_Cache_Helper::get_cache_prefix( 'coupons' ) . 'coupon_id_from_code_' . $data['post_title'], 'coupons' );
2207 }
2208 }
2209
2210 // Start the run again.
2211 if ( $coupon_id ) {
2212 return update_option( 'woocommerce_update_450_last_coupon_id', $coupon_id );
2213 }
2214
2215 delete_option( 'woocommerce_update_450_last_coupon_id' );
2216 return false;
2217 }
2218
2219 /**
2220 * Fixes product review count that might have been incorrect.
2221 *
2222 * See @link https://github.com/woocommerce/woocommerce/issues/27688.
2223 */
2224 function wc_update_500_fix_product_review_count() {
2225 global $wpdb;
2226
2227 $product_id = 0;
2228 $last_product_id = get_option( 'woocommerce_update_500_last_product_id', '0' );
2229
2230 $products_data = $wpdb->get_results(
2231 $wpdb->prepare(
2232 "
2233 SELECT post_id, meta_value
2234 FROM $wpdb->postmeta
2235 JOIN $wpdb->posts
2236 ON $wpdb->postmeta.post_id = $wpdb->posts.ID
2237 WHERE
2238 post_type = 'product'
2239 AND post_status = 'publish'
2240 AND post_id > %d
2241 AND meta_key = '_wc_review_count'
2242 ORDER BY post_id ASC
2243 LIMIT 10
2244 ",
2245 $last_product_id
2246 ),
2247 ARRAY_A
2248 );
2249
2250 if ( empty( $products_data ) ) {
2251 delete_option( 'woocommerce_update_500_last_product_id' );
2252 return false;
2253 }
2254
2255 $product_ids_to_check = array_column( $products_data, 'post_id' );
2256 $actual_review_counts = WC_Comments::get_review_counts_for_product_ids( $product_ids_to_check );
2257
2258 foreach ( $products_data as $product_data ) {
2259 $product_id = intval( $product_data['post_id'] );
2260 $current_review_count = intval( $product_data['meta_value'] );
2261
2262 if ( intval( $actual_review_counts[ $product_id ] ) !== $current_review_count ) {
2263 WC_Comments::clear_transients( $product_id );
2264 }
2265 }
2266
2267 // Start the run again.
2268 if ( $product_id ) {
2269 return update_option( 'woocommerce_update_500_last_product_id', $product_id );
2270 }
2271
2272 delete_option( 'woocommerce_update_500_last_product_id' );
2273 return false;
2274 }
2275
2276 /**
2277 * Update DB version to 5.0.0.
2278 */
2279 function wc_update_500_db_version() {
2280 WC_Install::update_db_version( '5.0.0' );
2281 }
2282
2283 /**
2284 * Creates the refund and returns policy page.
2285 *
2286 * See @link https://github.com/woocommerce/woocommerce/issues/29235.
2287 */
2288 function wc_update_560_create_refund_returns_page() {
2289 /**
2290 * Filter on the pages created to return what we expect.
2291 *
2292 * @param array $pages The default WC pages.
2293 */
2294 function filter_created_pages( $pages ) {
2295 $page_to_create = array( 'refund_returns' );
2296
2297 return array_intersect_key( $pages, array_flip( $page_to_create ) );
2298 }
2299
2300 add_filter( 'woocommerce_create_pages', 'filter_created_pages' );
2301
2302 WC_Install::create_pages();
2303
2304 remove_filter( 'woocommerce_create_pages', 'filter_created_pages' );
2305 }
2306
2307 /**
2308 * Update DB version to 5.6.0.
2309 */
2310 function wc_update_560_db_version() {
2311 WC_Install::update_db_version( '5.6.0' );
2312 }
2313
2314 /**
2315 * Migrate rate limit options to the new table.
2316 *
2317 * See @link https://github.com/woocommerce/woocommerce/issues/27103.
2318 */
2319 function wc_update_600_migrate_rate_limit_options() {
2320 global $wpdb;
2321
2322 $rate_limits = $wpdb->get_results(
2323 "
2324 SELECT option_name, option_value
2325 FROM $wpdb->options
2326 WHERE option_name LIKE 'woocommerce_rate_limit_add_payment_method_%'
2327 ",
2328 ARRAY_A
2329 );
2330 $prefix_length = strlen( 'woocommerce_rate_limit_' );
2331
2332 foreach ( $rate_limits as $rate_limit ) {
2333 $new_delay = (int) $rate_limit['option_value'] - time();
2334
2335 // Migrate the limit if it hasn't expired yet.
2336 if ( 0 < $new_delay ) {
2337 $action_id = substr( $rate_limit['option_name'], $prefix_length );
2338 WC_Rate_Limiter::set_rate_limit( $action_id, $new_delay );
2339 }
2340
2341 delete_option( $rate_limit['option_name'] );
2342 }
2343 }
2344
2345 /**
2346 * Update DB version to 6.0.0.
2347 */
2348 function wc_update_600_db_version() {
2349 WC_Install::update_db_version( '6.0.0' );
2350 }
2351
2352 /**
2353 * Create the product attributes lookup table and initiate its filling,
2354 * unless the table had been already created manually (via the tools page).
2355 *
2356 * @return false Always false, since the LookupDataStore class handles all the data filling process.
2357 */
2358 function wc_update_630_create_product_attributes_lookup_table() {
2359 $data_store = wc_get_container()->get( LookupDataStore::class );
2360 $data_regenerator = wc_get_container()->get( DataRegenerator::class );
2361
2362 /**
2363 * If the table exists and contains data, it was manually created by user before the migration ran.
2364 * If the table exists but is empty, it was likely created right now via dbDelta, so a table regenerations is needed (unless one is in progress already).
2365 */
2366 if ( ! $data_store->check_lookup_table_exists() || ( ! $data_store->lookup_table_has_data() && ! $data_store->regeneration_is_in_progress() ) ) {
2367 $data_regenerator->initiate_regeneration();
2368 }
2369
2370 return false;
2371 }
2372
2373 /**
2374 *
2375 * Update DB version to 6.3.0.
2376 */
2377 function wc_update_630_db_version() {
2378 WC_Install::update_db_version( '6.3.0' );
2379 }
2380
2381 /**
2382 * Create the primary key for the product attributes lookup table if it doesn't exist already.
2383 *
2384 * @return bool Always false.
2385 */
2386 function wc_update_640_add_primary_key_to_product_attributes_lookup_table() {
2387 wc_get_container()->get( DataRegenerator::class )->create_table_primary_index();
2388
2389 return false;
2390 }
2391
2392 /**
2393 *
2394 * Update DB version to 6.4.0.
2395 */
2396 function wc_update_640_db_version() {
2397 WC_Install::update_db_version( '6.4.0' );
2398 }
2399
2400 /**
2401 * Add the standard WooCommerce upload directories to the Approved Product Download Directories list
2402 * and start populating it based on existing product download URLs, but do not enable the feature
2403 * (for existing installations, a site admin should review and make a conscious decision to enable).
2404 */
2405 function wc_update_650_approved_download_directories() {
2406 $directory_sync = wc_get_container()->get( Download_Directories_Sync::class );
2407 $directory_sync->init_hooks();
2408 $directory_sync->init_feature( true, false );
2409 }
2410
2411 /**
2412 * In some cases, the approved download directories table may not have been successfully created during the update to
2413 * 6.5.0. If this was the case we will need to re-initialize the feature.
2414 */
2415 function wc_update_651_approved_download_directories() {
2416 global $wpdb;
2417
2418 $download_directories = wc_get_container()->get( Download_Directories::class );
2419 $directory_sync = wc_get_container()->get( Download_Directories_Sync::class );
2420
2421 // Check if at least 1 row exists, without scanning the entire table.
2422 $is_populated = (bool) $wpdb->get_var(
2423 'SELECT 1 FROM ' . $download_directories->get_table() . ' LIMIT 1'
2424 );
2425
2426 // If the table contains rules (or does not yet, but a sync is in-progress) we should do nothing else at this point.
2427 if ( $is_populated || $directory_sync->in_progress() ) {
2428 return;
2429 }
2430
2431 // Otherwise, it seems reasonable to assume that the feature was not initialized as expected during the update to
2432 // 6.5.0. Let's give that another try.
2433 $directory_sync->init_hooks();
2434 $directory_sync->init_feature( true, false );
2435 }
2436
2437 /**
2438 * Purges the comments count cache after 6.7.0 split reviews from the comments page.
2439 */
2440 function wc_update_670_purge_comments_count_cache() {
2441 if ( ! is_callable( 'WC_Comments::delete_comments_count_cache' ) ) {
2442 return;
2443 }
2444
2445 WC_Comments::delete_comments_count_cache();
2446 }
2447 /**
2448 * Remove unnecessary foreign keys.
2449 *
2450 * @return void
2451 */
2452 function wc_update_700_remove_download_log_fk() {
2453 global $wpdb;
2454
2455 $create_table_sql = $wpdb->get_var( "SHOW CREATE TABLE {$wpdb->prefix}wc_download_log", 1 );
2456
2457 if ( ! empty( $create_table_sql ) ) {
2458 if ( preg_match_all( '/CONSTRAINT `([^`]*)` FOREIGN KEY/', $create_table_sql, $matches ) && ! empty( $matches[1] ) ) {
2459 foreach ( $matches[1] as $foreign_key_name ) {
2460 $wpdb->query( "ALTER TABLE {$wpdb->prefix}wc_download_log DROP FOREIGN KEY `{$foreign_key_name}`" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
2461 }
2462 }
2463 }
2464 }
2465
2466 /**
2467 * Remove the transient data for recommended marketing extensions.
2468 */
2469 function wc_update_700_remove_recommended_marketing_plugins_transient() {
2470 delete_transient( 'wc_marketing_recommended_plugins' );
2471 }
2472
2473 /**
2474 * Update the New Zealand state codes in the database
2475 * after they were updated in code to the CLDR standard.
2476 */
2477 function wc_update_721_adjust_new_zealand_states() {
2478 return MigrationHelper::migrate_country_states(
2479 'NZ',
2480 array(
2481 'NL' => 'NTL',
2482 'AK' => 'AUK',
2483 'WA' => 'WKO',
2484 'BP' => 'BOP',
2485 'TK' => 'TKI',
2486 'GI' => 'GIS',
2487 'HB' => 'HKB',
2488 'MW' => 'MWT',
2489 'WE' => 'WGN',
2490 'NS' => 'NSN',
2491 'MB' => 'MBH',
2492 'TM' => 'TAS',
2493 'WC' => 'WTC',
2494 'CT' => 'CAN',
2495 'OT' => 'OTA',
2496 'SL' => 'STL',
2497 )
2498 );
2499 }
2500
2501 /**
2502 * Update the Ukraine state codes in the database
2503 * after they were updated in code to the CLDR standard.
2504 */
2505 function wc_update_721_adjust_ukraine_states() {
2506 return MigrationHelper::migrate_country_states(
2507 'UA',
2508 array(
2509 'VN' => 'UA05',
2510 'LH' => 'UA09',
2511 'VL' => 'UA07',
2512 'DP' => 'UA12',
2513 'DT' => 'UA14',
2514 'ZT' => 'UA18',
2515 'ZK' => 'UA21',
2516 'ZP' => 'UA23',
2517 'IF' => 'UA26',
2518 'KV' => 'UA32',
2519 'KH' => 'UA35',
2520 'LV' => 'UA46',
2521 'MY' => 'UA48',
2522 'OD' => 'UA51',
2523 'PL' => 'UA53',
2524 'RV' => 'UA56',
2525 'SM' => 'UA59',
2526 'TP' => 'UA61',
2527 'KK' => 'UA63',
2528 'KS' => 'UA65',
2529 'KM' => 'UA68',
2530 'CK' => 'UA71',
2531 'CH' => 'UA74',
2532 'CV' => 'UA77',
2533 )
2534 );
2535 }
2536
2537 /**
2538 * Update the New Zealand state codes in the database after they were updated in code to the CLDR standard.
2539 *
2540 * This is a simple wrapper for the corresponding 7.2.1 update function. The reason we do this (instead of
2541 * reusing the original function directly) is for better traceability in the Action Scheduler log, in case
2542 * of problems.
2543 */
2544 function wc_update_722_adjust_new_zealand_states() {
2545 return wc_update_721_adjust_new_zealand_states();
2546 }
2547
2548 /**
2549 * Update the Ukraine state codes in the database after they were updated in code to the CLDR standard.
2550 *
2551 * This is a simple wrapper for the corresponding 7.2.1 update function. The reason we do this (instead of
2552 * reusing the original function directly) is for better traceability in the Action Scheduler log, in case
2553 * of problems.
2554 */
2555 function wc_update_722_adjust_ukraine_states() {
2556 return wc_update_721_adjust_ukraine_states();
2557 }
2558
2559 /**
2560 * Add new columns date_paid and date_completed to wp_wc_order_stats table in order to provide the option
2561 * of using the dates in the reports
2562 */
2563 function wc_update_750_add_columns_to_order_stats_table() {
2564 global $wpdb;
2565
2566 $wpdb->query(
2567 "UPDATE {$wpdb->prefix}wc_order_stats AS order_stats
2568 INNER JOIN {$wpdb->postmeta} AS postmeta
2569 ON postmeta.post_id = order_stats.order_id
2570 and postmeta.meta_key = '_date_paid'
2571 SET order_stats.date_paid = IFNULL(FROM_UNIXTIME(postmeta.meta_value), '0000-00-00 00:00:00');"
2572 );
2573
2574 $wpdb->query(
2575 "UPDATE {$wpdb->prefix}wc_order_stats AS order_stats
2576 INNER JOIN {$wpdb->postmeta} AS postmeta
2577 ON postmeta.post_id = order_stats.order_id
2578 and postmeta.meta_key = '_date_completed'
2579 SET order_stats.date_completed = IFNULL(FROM_UNIXTIME(postmeta.meta_value), '0000-00-00 00:00:00');"
2580 );
2581 }
2582
2583 /**
2584 * Disable the experimental product management experience.
2585 *
2586 * @return void
2587 */
2588 function wc_update_750_disable_new_product_management_experience() {
2589 if ( 'yes' === get_option( 'woocommerce_new_product_management_enabled' ) ) {
2590 update_option( 'woocommerce_new_product_management_enabled', 'no' );
2591 }
2592 }
2593
2594 /**
2595 * Remove the multichannel marketing feature flag and options. This feature is now enabled by default.
2596 */
2597 function wc_update_770_remove_multichannel_marketing_feature_options() {
2598 delete_option( 'woocommerce_multichannel_marketing_enabled' );
2599 delete_option( 'woocommerce_marketing_overview_welcome_hidden' );
2600 }
2601
2602 /**
2603 * Migrate transaction data which was being incorrectly stored in the postmeta table to HPOS tables.
2604 *
2605 * @return bool Whether there are pending migration records.
2606 */
2607 function wc_update_810_migrate_transactional_metadata_for_hpos() {
2608 global $wpdb;
2609
2610 $data_synchronizer = wc_get_container()->get( DataSynchronizer::class );
2611 if ( ! $data_synchronizer->get_table_exists() ) {
2612 return false;
2613 }
2614
2615 $orders_table = OrdersTableDataStore::get_orders_table_name();
2616 $orders_meta_table = OrdersTableDataStore::get_meta_table_name();
2617
2618 /**
2619 * We are migrating payment_tokens meta that is stored in wp_postmeta table to the HPOS table. To do this with minimum db ops:
2620 * 1. We join postmeta table with wc_orders table directly, this filters out orders that are yet to be migrated and any post with non-order post type.
2621 * 2. A combination of filter on wc_orders_meta.meta_key = _payment_tokens in the join condition itself, along with a null check in a WHERE condition, allows us to only get the orders where the meta is not yet migrated.
2622 */
2623 $select_query = "
2624 SELECT post_id, '_payment_tokens', {$wpdb->postmeta}.meta_value
2625 FROM {$wpdb->postmeta}
2626 JOIN $orders_table ON {$wpdb->postmeta}.post_id = $orders_table.id
2627 LEFT JOIN $orders_meta_table ON $orders_meta_table.order_id = $orders_table.id AND $orders_meta_table.meta_key = '_payment_tokens'
2628 WHERE
2629 {$wpdb->postmeta}.meta_key = '_payment_tokens'
2630 AND $orders_meta_table.order_id IS NULL
2631 ";
2632
2633 // No need to get the data in application, we can insert directly. Sync setting does not matter as this data already exist in the post table. Limit the batch size to 250.
2634 $query =
2635 "
2636 INSERT INTO $orders_meta_table (order_id, meta_key, meta_value)
2637 $select_query
2638 LIMIT 250
2639 ";
2640 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- No user input in the query, everything hardcoded.
2641 $wpdb->query( $query );
2642
2643 // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- No user input in the query, everything hardcoded.
2644 $has_pending = $wpdb->query( "$select_query LIMIT 1;" );
2645
2646 return ! empty( $has_pending );
2647 }
2648
2649 /**
2650 * Remove the transient data for recommended marketing extensions.
2651 *
2652 * This is removed because it is not used anymore.
2653 * It is replaced by `woocommerce_admin_marketing_recommendations_specs` transient that is created by `MarketingRecommendationsDataSourcePoller`.
2654 */
2655 function wc_update_860_remove_recommended_marketing_plugins_transient() {
2656 delete_transient( 'wc_marketing_recommended_plugins' );
2657 }
2658
2659 /**
2660 * Create an .htaccess file and an empty index.html file to prevent listing of the default transient files directory,
2661 * if the directory exists.
2662 */
2663 function wc_update_870_prevent_listing_of_transient_files_directory() {
2664 global $wp_filesystem;
2665
2666 $default_transient_files_dir = untrailingslashit( wp_upload_dir()['basedir'] ) . '/woocommerce_transient_files';
2667 if ( ! is_dir( $default_transient_files_dir ) ) {
2668 return;
2669 }
2670
2671 require_once ABSPATH . 'wp-admin/includes/file.php';
2672 \WP_Filesystem();
2673 $wp_filesystem->put_contents( $default_transient_files_dir . '/.htaccess', 'deny from all' );
2674 $wp_filesystem->put_contents( $default_transient_files_dir . '/index.html', '' );
2675 }
2676
2677 /**
2678 * If it exists, remove the inbox note that asks users to connect to `Woo.com`.
2679 */
2680 function wc_update_890_update_connect_to_woocommerce_note() {
2681 $note = Notes::get_note_by_name( WooSubscriptionsNotes::CONNECTION_NOTE_NAME );
2682 if ( ! is_a( $note, 'Automattic\WooCommerce\Admin\Notes\Note' ) ) {
2683 return;
2684 }
2685 if ( ! str_contains( $note->get_title(), 'Woo.com' ) ) {
2686 return;
2687 }
2688 if ( $note->get_status() !== Note::E_WC_ADMIN_NOTE_SNOOZED && $note->get_status() !== Note::E_WC_ADMIN_NOTE_UNACTIONED ) {
2689 return;
2690 }
2691 Notes::delete_notes_with_name( WooSubscriptionsNotes::CONNECTION_NOTE_NAME );
2692 }
2693
2694 /**
2695 * Disables the PayPal Standard gateway for stores that aren't using it.
2696 *
2697 * PayPal Standard has been deprecated since WooCommerce 5.5, but there are some stores that have it showing up in their
2698 * list of available Payment methods even if it's not setup. In WooCommerce 8.9 we will disable PayPal Standard for those stores
2699 * to reduce the amount of new connections to the legacy gateway.
2700 *
2701 * Shows an admin notice to inform the store owner that PayPal Standard has been disabled and suggests installing PayPal Payments.
2702 */
2703 function wc_update_890_update_paypal_standard_load_eligibility() {
2704 $paypal = class_exists( 'WC_Gateway_Paypal' ) ? new WC_Gateway_Paypal() : null;
2705
2706 if ( ! $paypal ) {
2707 return;
2708 }
2709
2710 // If PayPal is enabled or set to load, but the store hasn't setup PayPal Standard live API keys and doesn't have any PayPal Orders, disable it.
2711 if ( ( 'yes' === $paypal->enabled || 'yes' === $paypal->get_option( '_should_load' ) ) && ! $paypal->get_option( 'api_username' ) && ! $paypal->has_paypal_orders() ) {
2712 $paypal->update_option( '_should_load', wc_bool_to_string( false ) );
2713 }
2714 }
2715
2716 /**
2717 * Create the woocommerce_history_of_autoinstalled_plugins option if it doesn't exist
2718 * as a copy of woocommerce_autoinstalled_plugins if it exists.
2719 */
2720 function wc_update_891_create_plugin_autoinstall_history_option() {
2721 $autoinstalled_plugins_history_info = get_site_option( 'woocommerce_history_of_autoinstalled_plugins' );
2722 if ( false === $autoinstalled_plugins_history_info ) {
2723 $autoinstalled_plugins_info = get_site_option( 'woocommerce_autoinstalled_plugins' );
2724 if ( false !== $autoinstalled_plugins_info ) {
2725 update_site_option( 'woocommerce_history_of_autoinstalled_plugins', $autoinstalled_plugins_info );
2726 }
2727 }
2728 }
2729
2730 /**
2731 * Add woocommerce_show_lys_tour.
2732 */
2733 function wc_update_910_add_launch_your_store_tour_option() {
2734 add_option( 'woocommerce_show_lys_tour', 'yes' );
2735 }
2736
2737 /**
2738 * Add woocommerce_hooked_blocks_version option for existing stores that are using a theme that supports the Block Hooks API
2739 */
2740 function wc_update_920_add_wc_hooked_blocks_version_option() {
2741 if ( ! wc_current_theme_is_fse_theme() && ! current_theme_supports( 'block-template-parts' ) ) {
2742 return;
2743 }
2744
2745 $option_name = 'woocommerce_hooked_blocks_version';
2746 $option_value = get_option( $option_name );
2747
2748 // If the option already exists, we don't need to do anything.
2749 if ( false !== $option_value ) {
2750 return;
2751 }
2752
2753 /**
2754 * A list of theme slugs to execute this with.
2755 * We are applying this filter to allow for the list to be extended by third-parties who were already using it.
2756 *
2757 * @since 8.4.0
2758 */
2759 $theme_include_list = apply_filters( 'woocommerce_hooked_blocks_theme_include_list', array( 'Twenty Twenty-Four', 'Twenty Twenty-Three', 'Twenty Twenty-Two', 'Tsubaki', 'Zaino', 'Thriving Artist', 'Amulet', 'Tazza' ) );
2760 $active_theme_name = wp_get_theme()->get( 'Name' );
2761 $should_set_hooked_blocks_version = in_array( $active_theme_name, $theme_include_list, true );
2762
2763 if ( $should_set_hooked_blocks_version ) {
2764 // Set 8.4.0 as the version for existing stores that are using a theme that supports the Block Hooks API.
2765 // This will ensure that the Block Hooks API is enabled for these stores and works as expected.
2766 // Existing stores that aren't running approved block themes will not have the Block Hooks API enabled.
2767 add_option( $option_name, '8.4.0' );
2768 } else {
2769 // For block themes that aren't approved themes set this option to "no" to completely disable hooked blocks.
2770 // This means we can assume the absence of the option is when a site is switching from a classic theme to a block theme for the first time.
2771 // Note: We have to use "no" instead of false since the latter is the default value for the option if it doesn't exist.
2772 add_option( $option_name, 'no' );
2773 }
2774 }
2775
2776 /**
2777 * Remove user meta associated with the keys '_last_order', '_order_count' and '_money_spent'.
2778 *
2779 * New keys are now used for these, to improve compatibility with multisite networks.
2780 *
2781 * @return void
2782 */
2783 function wc_update_910_remove_obsolete_user_meta() {
2784 global $wpdb;
2785
2786 $deletions = $wpdb->query(
2787 "
2788 DELETE FROM $wpdb->usermeta
2789 WHERE meta_key IN (
2790 '_last_order',
2791 '_order_count',
2792 '_money_spent'
2793 )
2794 "
2795 );
2796
2797 $logger = wc_get_logger();
2798
2799 if ( null === $logger ) {
2800 return;
2801 }
2802
2803 if ( false === $deletions ) {
2804 $logger->notice(
2805 'During the update to 9.1.0, WooCommerce attempted to remove user meta with the keys "_last_order", "_order_count" and "_money_spent" but was unable to do so.',
2806 array(
2807 'source' => 'wc-updater',
2808 )
2809 );
2810 } else {
2811 $logger->info(
2812 sprintf(
2813 1 === $deletions
2814 ? 'During the update to 9.1.0, WooCommerce removed %d user meta row associated with the meta keys "_last_order", "_order_count" or "_money_spent".'
2815 : 'During the update to 9.1.0, WooCommerce removed %d user meta rows associated with the meta keys "_last_order", "_order_count" or "_money_spent".',
2816 number_format_i18n( $deletions )
2817 ),
2818 array(
2819 'source' => 'wc-updater',
2820 )
2821 );
2822 }
2823 }
2824
2825 /**
2826 * Add woocommerce_coming_soon option when it is not currently present.
2827 */
2828 function wc_update_930_add_woocommerce_coming_soon_option() {
2829 add_option( 'woocommerce_coming_soon', 'no' );
2830 }
2831
2832 /**
2833 * Migrate Launch Your Store tour meta keys to the woocommerce_meta user data fields.
2834 */
2835 function wc_update_930_migrate_user_meta_for_launch_your_store_tour() {
2836 // Rename `woocommerce_launch_your_store_tour_hidden` meta key to `woocommerce_admin_launch_your_store_tour_hidden`.
2837 global $wpdb;
2838 $wpdb->query(
2839 $wpdb->prepare(
2840 "UPDATE {$wpdb->usermeta}
2841 SET meta_key = %s
2842 WHERE meta_key = %s",
2843 'woocommerce_admin_launch_your_store_tour_hidden',
2844 'woocommerce_launch_your_store_tour_hidden'
2845 )
2846 );
2847
2848 // Rename `woocommerce_coming_soon_banner_dismissed` meta key to `woocommerce_admin_coming_soon_banner_dismissed`.
2849 $wpdb->query(
2850 $wpdb->prepare(
2851 "UPDATE {$wpdb->usermeta}
2852 SET meta_key = %s
2853 WHERE meta_key = %s",
2854 'woocommerce_admin_coming_soon_banner_dismissed',
2855 'woocommerce_coming_soon_banner_dismissed'
2856 )
2857 );
2858 }
2859
2860 /**
2861 * Recreate FTS index if it already exists, so that phone number can be added to the index.
2862 */
2863 function wc_update_940_add_phone_to_order_address_fts_index(): void {
2864 $fts_already_exists = get_option( CustomOrdersTableController::HPOS_FTS_ADDRESS_INDEX_CREATED_OPTION ) === 'yes';
2865 if ( ! $fts_already_exists ) {
2866 return;
2867 }
2868
2869 $hpos_controller = wc_get_container()->get( CustomOrdersTableController::class );
2870 $result = $hpos_controller->recreate_order_address_fts_index();
2871 if ( ! $result['status'] ) {
2872 if ( class_exists( 'WC_Admin_Settings ' ) ) {
2873 WC_Admin_Settings::add_error( $result['message'] );
2874 }
2875 }
2876 }
2877
2878 /**
2879 * Remove user meta associated with the key 'woocommerce_admin_help_panel_highlight_shown'.
2880 *
2881 * This key is no longer needed since the help panel spotlight tour has been removed.
2882 *
2883 * @return void
2884 */
2885 function wc_update_940_remove_help_panel_highlight_shown() {
2886 global $wpdb;
2887
2888 $meta_key = 'woocommerce_admin_help_panel_highlight_shown';
2889
2890 $deletions = $wpdb->query(
2891 $wpdb->prepare(
2892 "DELETE FROM $wpdb->usermeta WHERE meta_key = %s",
2893 $meta_key
2894 )
2895 );
2896
2897 // Get the WooCommerce logger to track the results of the deletion.
2898 $logger = wc_get_logger();
2899
2900 if ( null === $logger ) {
2901 return;
2902 }
2903
2904 if ( false === $deletions ) {
2905 $logger->notice(
2906 'During the update to 9.4.0, WooCommerce attempted to remove user meta with the key "woocommerce_admin_help_panel_highlight_shown", but was unable to do so.',
2907 array(
2908 'source' => 'wc-updater',
2909 )
2910 );
2911 } else {
2912 $logger->info(
2913 sprintf(
2914 1 === $deletions
2915 ? 'During the update to 9.4.0, WooCommerce removed %d user meta row associated with the meta key "woocommerce_admin_help_panel_highlight_shown".'
2916 : 'During the update to 9.4.0, WooCommerce removed %d user meta rows associated with the meta key "woocommerce_admin_help_panel_highlight_shown".',
2917 number_format_i18n( $deletions )
2918 ),
2919 array(
2920 'source' => 'wc-updater',
2921 )
2922 );
2923 }
2924 }
2925
2926 /**
2927 * Autoloads woocommerce_allow_tracking option.
2928 */
2929 function wc_update_950_tracking_option_autoload() {
2930 $options = array(
2931 'woocommerce_allow_tracking' => 'yes',
2932 );
2933 wp_set_option_autoload_values( $options );
2934 }
2935
2936 /**
2937 * Update the base color for emails as part of the WooCommerce rebranding,
2938 * but only if the user hasn't specified a custom color.
2939 */
2940 function wc_update_961_migrate_default_email_base_color() {
2941 $color = get_option( 'woocommerce_email_base_color' );
2942 if ( '#7f54b3' === $color ) {
2943 update_option( 'woocommerce_email_base_color', '#720eec' );
2944 }
2945 }
2946