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