PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 6.9.3
WooCommerce v6.9.3
10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / includes / wc-update-functions.php
woocommerce / includes Last commit date
abstracts 3 years ago admin 3 years ago blocks 5 years ago cli 3 years ago customizer 3 years ago data-stores 3 years ago emails 3 years ago export 3 years ago gateways 3 years ago import 4 years ago integrations 4 years ago interfaces 4 years ago legacy 3 years ago libraries 3 years ago log-handlers 4 years ago payment-tokens 5 years ago queue 4 years ago react-admin 3 years ago rest-api 3 years ago shipping 4 years ago shortcodes 4 years ago theme-support 3 years ago tracks 3 years ago traits 5 years ago walkers 5 years ago wccom-site 5 years ago widgets 4 years ago class-wc-ajax.php 3 years ago class-wc-api.php 4 years ago class-wc-auth.php 4 years ago class-wc-autoloader.php 5 years ago class-wc-background-emailer.php 5 years ago class-wc-background-updater.php 5 years ago class-wc-breadcrumb.php 5 years ago class-wc-cache-helper.php 4 years ago class-wc-cart-fees.php 5 years ago class-wc-cart-session.php 3 years ago class-wc-cart-totals.php 4 years ago class-wc-cart.php 4 years ago class-wc-checkout.php 4 years ago class-wc-cli.php 3 years ago class-wc-comments.php 3 years ago class-wc-countries.php 4 years ago class-wc-coupon.php 4 years ago class-wc-customer-download-log.php 5 years ago class-wc-customer-download.php 4 years ago class-wc-customer.php 4 years ago class-wc-data-exception.php 8 years ago class-wc-data-store.php 3 years ago class-wc-datetime.php 4 years ago class-wc-deprecated-action-hooks.php 8 years ago class-wc-deprecated-filter-hooks.php 4 years ago class-wc-discounts.php 3 years ago class-wc-download-handler.php 4 years ago class-wc-emails.php 3 years ago class-wc-embed.php 5 years ago class-wc-form-handler.php 4 years ago class-wc-frontend-scripts.php 3 years ago class-wc-geo-ip.php 4 years ago class-wc-geolite-integration.php 6 years ago class-wc-geolocation.php 3 years ago class-wc-https.php 4 years ago class-wc-install.php 3 years ago class-wc-integrations.php 5 years ago class-wc-log-levels.php 5 years ago class-wc-logger.php 4 years ago class-wc-meta-data.php 4 years ago class-wc-order-factory.php 3 years ago class-wc-order-item-coupon.php 4 years ago class-wc-order-item-fee.php 4 years ago class-wc-order-item-meta.php 4 years ago class-wc-order-item-product.php 4 years ago class-wc-order-item-shipping.php 4 years ago class-wc-order-item-tax.php 4 years ago class-wc-order-item.php 4 years ago class-wc-order-query.php 4 years ago class-wc-order-refund.php 3 years ago class-wc-order.php 3 years ago class-wc-payment-gateways.php 4 years ago class-wc-payment-tokens.php 5 years ago class-wc-post-data.php 3 years ago class-wc-post-types.php 3 years ago class-wc-privacy-background-process.php 5 years ago class-wc-privacy-erasers.php 4 years ago class-wc-privacy-exporters.php 4 years ago class-wc-privacy.php 4 years ago class-wc-product-attribute.php 4 years ago class-wc-product-download.php 4 years ago class-wc-product-external.php 5 years ago class-wc-product-factory.php 5 years ago class-wc-product-grouped.php 8 years ago class-wc-product-query.php 5 years ago class-wc-product-simple.php 3 years ago class-wc-product-variable.php 4 years ago class-wc-product-variation.php 4 years ago class-wc-query.php 4 years ago class-wc-rate-limiter.php 4 years ago class-wc-regenerate-images-request.php 3 years ago class-wc-regenerate-images.php 3 years ago class-wc-register-wp-admin-settings.php 4 years ago class-wc-rest-authentication.php 5 years ago class-wc-rest-exception.php 5 years ago class-wc-session-handler.php 4 years ago class-wc-shipping-rate.php 4 years ago class-wc-shipping-zone.php 5 years ago class-wc-shipping-zones.php 5 years ago class-wc-shipping.php 4 years ago class-wc-shortcodes.php 5 years ago class-wc-structured-data.php 5 years ago class-wc-tax.php 4 years ago class-wc-template-loader.php 4 years ago class-wc-tracker.php 4 years ago class-wc-validation.php 5 years ago class-wc-webhook.php 3 years ago class-woocommerce.php 3 years ago wc-account-functions.php 5 years ago wc-attribute-functions.php 3 years ago wc-cart-functions.php 4 years ago wc-conditional-functions.php 4 years ago wc-core-functions.php 3 years ago wc-coupon-functions.php 5 years ago wc-deprecated-functions.php 4 years ago wc-formatting-functions.php 3 years ago wc-notice-functions.php 5 years ago wc-order-functions.php 3 years ago wc-order-item-functions.php 5 years ago wc-page-functions.php 5 years ago wc-product-functions.php 3 years ago wc-rest-functions.php 3 years ago wc-stock-functions.php 4 years ago wc-template-functions.php 3 years ago wc-template-hooks.php 5 years ago wc-term-functions.php 3 years ago wc-update-functions.php 3 years ago wc-user-functions.php 3 years ago wc-webhook-functions.php 4 years ago wc-widget-functions.php 5 years ago
wc-update-functions.php
2444 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\Internal\AssignDefaultCategory;
22 use Automattic\WooCommerce\Internal\ProductAttributesLookup\DataRegenerator;
23 use Automattic\WooCommerce\Internal\ProductAttributesLookup\LookupDataStore;
24 use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Register as Download_Directories;
25 use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Synchronize as Download_Directories_Sync;
26
27 /**
28 * Update file paths for 2.0
29 *
30 * @return void
31 */
32 function wc_update_200_file_paths() {
33 global $wpdb;
34
35 // Upgrade old style files paths to support multiple file paths.
36 $existing_file_paths = $wpdb->get_results( "SELECT meta_value, meta_id, post_id FROM {$wpdb->postmeta} WHERE meta_key = '_file_path' AND meta_value != '';" );
37
38 if ( $existing_file_paths ) {
39
40 foreach ( $existing_file_paths as $existing_file_path ) {
41
42 $old_file_path = trim( $existing_file_path->meta_value );
43
44 if ( ! empty( $old_file_path ) ) {
45 // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
46 $file_paths = serialize( array( md5( $old_file_path ) => $old_file_path ) );
47
48 $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 ) );
49
50 $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 ) );
51
52 }
53 }
54 }
55 }
56
57 /**
58 * Update permalinks for 2.0
59 *
60 * @return void
61 */
62 function wc_update_200_permalinks() {
63 // Setup default permalinks if shop page is defined.
64 $permalinks = get_option( 'woocommerce_permalinks' );
65 $shop_page_id = wc_get_page_id( 'shop' );
66
67 if ( empty( $permalinks ) && $shop_page_id > 0 ) {
68
69 $base_slug = $shop_page_id > 0 && get_post( $shop_page_id ) ? get_page_uri( $shop_page_id ) : 'shop';
70
71 $category_base = 'yes' === get_option( 'woocommerce_prepend_shop_page_to_urls' ) ? trailingslashit( $base_slug ) : '';
72 $category_slug = get_option( 'woocommerce_product_category_slug' ) ? get_option( 'woocommerce_product_category_slug' ) : _x( 'product-category', 'slug', 'woocommerce' );
73 $tag_slug = get_option( 'woocommerce_product_tag_slug' ) ? get_option( 'woocommerce_product_tag_slug' ) : _x( 'product-tag', 'slug', 'woocommerce' );
74
75 if ( 'yes' === get_option( 'woocommerce_prepend_shop_page_to_products' ) ) {
76 $product_base = trailingslashit( $base_slug );
77 } else {
78 $product_slug = get_option( 'woocommerce_product_slug' );
79 if ( false !== $product_slug && ! empty( $product_slug ) ) {
80 $product_base = trailingslashit( $product_slug );
81 } else {
82 $product_base = trailingslashit( _x( 'product', 'slug', 'woocommerce' ) );
83 }
84 }
85
86 if ( 'yes' === get_option( 'woocommerce_prepend_category_to_products' ) ) {
87 $product_base .= trailingslashit( '%product_cat%' );
88 }
89
90 $permalinks = array(
91 'product_base' => untrailingslashit( $product_base ),
92 'category_base' => untrailingslashit( $category_base . $category_slug ),
93 'attribute_base' => untrailingslashit( $category_base ),
94 'tag_base' => untrailingslashit( $category_base . $tag_slug ),
95 );
96
97 update_option( 'woocommerce_permalinks', $permalinks );
98 }
99 }
100
101 /**
102 * Update sub-category display options for 2.0
103 *
104 * @return void
105 */
106 function wc_update_200_subcat_display() {
107 // Update subcat display settings.
108 if ( 'yes' === get_option( 'woocommerce_shop_show_subcategories' ) ) {
109 if ( 'yes' === get_option( 'woocommerce_hide_products_when_showing_subcategories' ) ) {
110 update_option( 'woocommerce_shop_page_display', 'subcategories' );
111 } else {
112 update_option( 'woocommerce_shop_page_display', 'both' );
113 }
114 }
115
116 if ( 'yes' === get_option( 'woocommerce_show_subcategories' ) ) {
117 if ( 'yes' === get_option( 'woocommerce_hide_products_when_showing_subcategories' ) ) {
118 update_option( 'woocommerce_category_archive_display', 'subcategories' );
119 } else {
120 update_option( 'woocommerce_category_archive_display', 'both' );
121 }
122 }
123 }
124
125 /**
126 * Update tax rates for 2.0
127 *
128 * @return void
129 */
130 function wc_update_200_taxrates() {
131 global $wpdb;
132
133 // Update tax rates.
134 $loop = 0;
135 $tax_rates = get_option( 'woocommerce_tax_rates' );
136
137 if ( $tax_rates ) {
138 foreach ( $tax_rates as $tax_rate ) {
139
140 foreach ( $tax_rate['countries'] as $country => $states ) {
141
142 $states = array_reverse( $states );
143
144 foreach ( $states as $state ) {
145
146 if ( '*' === $state ) {
147 $state = '';
148 }
149
150 $wpdb->insert(
151 $wpdb->prefix . 'woocommerce_tax_rates',
152 array(
153 'tax_rate_country' => $country,
154 'tax_rate_state' => $state,
155 'tax_rate' => $tax_rate['rate'],
156 'tax_rate_name' => $tax_rate['label'],
157 'tax_rate_priority' => 1,
158 'tax_rate_compound' => ( 'yes' === $tax_rate['compound'] ) ? 1 : 0,
159 'tax_rate_shipping' => ( 'yes' === $tax_rate['shipping'] ) ? 1 : 0,
160 'tax_rate_order' => $loop,
161 'tax_rate_class' => $tax_rate['class'],
162 )
163 );
164
165 $loop++;
166 }
167 }
168 }
169 }
170
171 $local_tax_rates = get_option( 'woocommerce_local_tax_rates' );
172
173 if ( $local_tax_rates ) {
174 foreach ( $local_tax_rates as $tax_rate ) {
175
176 $location_type = ( 'postcode' === $tax_rate['location_type'] ) ? 'postcode' : 'city';
177
178 if ( '*' === $tax_rate['state'] ) {
179 $tax_rate['state'] = '';
180 }
181
182 $wpdb->insert(
183 $wpdb->prefix . 'woocommerce_tax_rates',
184 array(
185 'tax_rate_country' => $tax_rate['country'],
186 'tax_rate_state' => $tax_rate['state'],
187 'tax_rate' => $tax_rate['rate'],
188 'tax_rate_name' => $tax_rate['label'],
189 'tax_rate_priority' => 2,
190 'tax_rate_compound' => ( 'yes' === $tax_rate['compound'] ) ? 1 : 0,
191 'tax_rate_shipping' => ( 'yes' === $tax_rate['shipping'] ) ? 1 : 0,
192 'tax_rate_order' => $loop,
193 'tax_rate_class' => $tax_rate['class'],
194 )
195 );
196
197 $tax_rate_id = $wpdb->insert_id;
198
199 if ( $tax_rate['locations'] ) {
200 foreach ( $tax_rate['locations'] as $location ) {
201
202 $wpdb->insert(
203 $wpdb->prefix . 'woocommerce_tax_rate_locations',
204 array(
205 'location_code' => $location,
206 'tax_rate_id' => $tax_rate_id,
207 'location_type' => $location_type,
208 )
209 );
210
211 }
212 }
213
214 $loop++;
215 }
216 }
217
218 update_option( 'woocommerce_tax_rates_backup', $tax_rates );
219 update_option( 'woocommerce_local_tax_rates_backup', $local_tax_rates );
220 delete_option( 'woocommerce_tax_rates' );
221 delete_option( 'woocommerce_local_tax_rates' );
222 }
223
224 /**
225 * Update order item line items for 2.0
226 *
227 * @return void
228 */
229 function wc_update_200_line_items() {
230 global $wpdb;
231
232 // Now its time for the massive update to line items - move them to the new DB tables.
233 // Reverse with UPDATE `wpwc_postmeta` SET meta_key = '_order_items' WHERE meta_key = '_order_items_old'.
234 $order_item_rows = $wpdb->get_results(
235 "SELECT meta_value, post_id FROM {$wpdb->postmeta} WHERE meta_key = '_order_items'"
236 );
237
238 foreach ( $order_item_rows as $order_item_row ) {
239
240 $order_items = (array) maybe_unserialize( $order_item_row->meta_value );
241
242 foreach ( $order_items as $order_item ) {
243
244 if ( ! isset( $order_item['line_total'] ) && isset( $order_item['taxrate'] ) && isset( $order_item['cost'] ) ) {
245 $order_item['line_tax'] = number_format( ( $order_item['cost'] * $order_item['qty'] ) * ( $order_item['taxrate'] / 100 ), 2, '.', '' );
246 $order_item['line_total'] = $order_item['cost'] * $order_item['qty'];
247 $order_item['line_subtotal_tax'] = $order_item['line_tax'];
248 $order_item['line_subtotal'] = $order_item['line_total'];
249 }
250
251 $order_item['line_tax'] = isset( $order_item['line_tax'] ) ? $order_item['line_tax'] : 0;
252 $order_item['line_total'] = isset( $order_item['line_total'] ) ? $order_item['line_total'] : 0;
253 $order_item['line_subtotal_tax'] = isset( $order_item['line_subtotal_tax'] ) ? $order_item['line_subtotal_tax'] : 0;
254 $order_item['line_subtotal'] = isset( $order_item['line_subtotal'] ) ? $order_item['line_subtotal'] : 0;
255
256 $item_id = wc_add_order_item(
257 $order_item_row->post_id,
258 array(
259 'order_item_name' => $order_item['name'],
260 'order_item_type' => 'line_item',
261 )
262 );
263
264 // Add line item meta.
265 if ( $item_id ) {
266 wc_add_order_item_meta( $item_id, '_qty', absint( $order_item['qty'] ) );
267 wc_add_order_item_meta( $item_id, '_tax_class', $order_item['tax_class'] );
268 wc_add_order_item_meta( $item_id, '_product_id', $order_item['id'] );
269 wc_add_order_item_meta( $item_id, '_variation_id', $order_item['variation_id'] );
270 wc_add_order_item_meta( $item_id, '_line_subtotal', wc_format_decimal( $order_item['line_subtotal'] ) );
271 wc_add_order_item_meta( $item_id, '_line_subtotal_tax', wc_format_decimal( $order_item['line_subtotal_tax'] ) );
272 wc_add_order_item_meta( $item_id, '_line_total', wc_format_decimal( $order_item['line_total'] ) );
273 wc_add_order_item_meta( $item_id, '_line_tax', wc_format_decimal( $order_item['line_tax'] ) );
274
275 $meta_rows = array();
276
277 // Insert meta.
278 if ( ! empty( $order_item['item_meta'] ) ) {
279 foreach ( $order_item['item_meta'] as $key => $meta ) {
280 // Backwards compatibility.
281 if ( is_array( $meta ) && isset( $meta['meta_name'] ) ) {
282 $meta_rows[] = '(' . $item_id . ',"' . esc_sql( $meta['meta_name'] ) . '","' . esc_sql( $meta['meta_value'] ) . '")';
283 } else {
284 $meta_rows[] = '(' . $item_id . ',"' . esc_sql( $key ) . '","' . esc_sql( $meta ) . '")';
285 }
286 }
287 }
288
289 // Insert meta rows at once.
290 if ( count( $meta_rows ) > 0 ) {
291 $wpdb->query(
292 $wpdb->prepare(
293 "INSERT INTO {$wpdb->prefix}woocommerce_order_itemmeta ( order_item_id, meta_key, meta_value )
294 VALUES " . implode( ',', $meta_rows ) . ';', // @codingStandardsIgnoreLine
295 $order_item_row->post_id
296 )
297 );
298 }
299
300 // Delete from DB (rename).
301 $wpdb->query(
302 $wpdb->prepare(
303 "UPDATE {$wpdb->postmeta}
304 SET meta_key = '_order_items_old'
305 WHERE meta_key = '_order_items'
306 AND post_id = %d",
307 $order_item_row->post_id
308 )
309 );
310 }
311
312 unset( $meta_rows, $item_id, $order_item );
313 }
314 }
315
316 // Do the same kind of update for order_taxes - move to lines.
317 // Reverse with UPDATE `wpwc_postmeta` SET meta_key = '_order_taxes' WHERE meta_key = '_order_taxes_old'.
318 $order_tax_rows = $wpdb->get_results(
319 "SELECT meta_value, post_id FROM {$wpdb->postmeta}
320 WHERE meta_key = '_order_taxes'"
321 );
322
323 foreach ( $order_tax_rows as $order_tax_row ) {
324
325 $order_taxes = (array) maybe_unserialize( $order_tax_row->meta_value );
326
327 if ( ! empty( $order_taxes ) ) {
328 foreach ( $order_taxes as $order_tax ) {
329
330 if ( ! isset( $order_tax['label'] ) || ! isset( $order_tax['cart_tax'] ) || ! isset( $order_tax['shipping_tax'] ) ) {
331 continue;
332 }
333
334 $item_id = wc_add_order_item(
335 $order_tax_row->post_id,
336 array(
337 'order_item_name' => $order_tax['label'],
338 'order_item_type' => 'tax',
339 )
340 );
341
342 // Add line item meta.
343 if ( $item_id ) {
344 wc_add_order_item_meta( $item_id, 'compound', absint( isset( $order_tax['compound'] ) ? $order_tax['compound'] : 0 ) );
345 wc_add_order_item_meta( $item_id, 'tax_amount', wc_clean( $order_tax['cart_tax'] ) );
346 wc_add_order_item_meta( $item_id, 'shipping_tax_amount', wc_clean( $order_tax['shipping_tax'] ) );
347 }
348
349 // Delete from DB (rename).
350 $wpdb->query(
351 $wpdb->prepare(
352 "UPDATE {$wpdb->postmeta}
353 SET meta_key = '_order_taxes_old'
354 WHERE meta_key = '_order_taxes'
355 AND post_id = %d",
356 $order_tax_row->post_id
357 )
358 );
359 }
360 }
361 }
362 }
363
364 /**
365 * Update image settings for 2.0
366 *
367 * @return void
368 */
369 function wc_update_200_images() {
370 // Grab the pre 2.0 Image options and use to populate the new image options settings,
371 // cleaning up afterwards like nice people do.
372 foreach ( array( 'catalog', 'single', 'thumbnail' ) as $value ) {
373
374 $old_settings = array_filter(
375 array(
376 'width' => get_option( 'woocommerce_' . $value . '_image_width' ),
377 'height' => get_option( 'woocommerce_' . $value . '_image_height' ),
378 'crop' => get_option( 'woocommerce_' . $value . '_image_crop' ),
379 )
380 );
381
382 if ( ! empty( $old_settings ) && update_option( 'shop_' . $value . '_image_size', $old_settings ) ) {
383
384 delete_option( 'woocommerce_' . $value . '_image_width' );
385 delete_option( 'woocommerce_' . $value . '_image_height' );
386 delete_option( 'woocommerce_' . $value . '_image_crop' );
387
388 }
389 }
390 }
391
392 /**
393 * Update DB version for 2.0
394 *
395 * @return void
396 */
397 function wc_update_200_db_version() {
398 WC_Install::update_db_version( '2.0.0' );
399 }
400
401 /**
402 * Update Brazilian States for 2.0.9
403 *
404 * @return void
405 */
406 function wc_update_209_brazillian_state() {
407 global $wpdb;
408
409 // phpcs:disable WordPress.DB.SlowDBQuery
410
411 // Update brazillian state codes.
412 $wpdb->update(
413 $wpdb->postmeta,
414 array(
415 'meta_value' => 'BA',
416 ),
417 array(
418 'meta_key' => '_billing_state',
419 'meta_value' => 'BH',
420 )
421 );
422 $wpdb->update(
423 $wpdb->postmeta,
424 array(
425 'meta_value' => 'BA',
426 ),
427 array(
428 'meta_key' => '_shipping_state',
429 'meta_value' => 'BH',
430 )
431 );
432 $wpdb->update(
433 $wpdb->usermeta,
434 array(
435 'meta_value' => 'BA',
436 ),
437 array(
438 'meta_key' => 'billing_state',
439 'meta_value' => 'BH',
440 )
441 );
442 $wpdb->update(
443 $wpdb->usermeta,
444 array(
445 'meta_value' => 'BA',
446 ),
447 array(
448 'meta_key' => 'shipping_state',
449 'meta_value' => 'BH',
450 )
451 );
452
453 // phpcs:enable WordPress.DB.SlowDBQuery
454 }
455
456 /**
457 * Update DB version for 2.0.9
458 *
459 * @return void
460 */
461 function wc_update_209_db_version() {
462 WC_Install::update_db_version( '2.0.9' );
463 }
464
465 /**
466 * Remove pages for 2.1
467 *
468 * @return void
469 */
470 function wc_update_210_remove_pages() {
471 // Pages no longer used.
472 wp_trash_post( get_option( 'woocommerce_pay_page_id' ) );
473 wp_trash_post( get_option( 'woocommerce_thanks_page_id' ) );
474 wp_trash_post( get_option( 'woocommerce_view_order_page_id' ) );
475 wp_trash_post( get_option( 'woocommerce_change_password_page_id' ) );
476 wp_trash_post( get_option( 'woocommerce_edit_address_page_id' ) );
477 wp_trash_post( get_option( 'woocommerce_lost_password_page_id' ) );
478 }
479
480 /**
481 * Update file paths to support multiple files for 2.1
482 *
483 * @return void
484 */
485 function wc_update_210_file_paths() {
486 global $wpdb;
487
488 // Upgrade file paths to support multiple file paths + names etc.
489 $existing_file_paths = $wpdb->get_results( "SELECT meta_value, meta_id FROM {$wpdb->postmeta} WHERE meta_key = '_file_paths' AND meta_value != '';" );
490
491 if ( $existing_file_paths ) {
492
493 foreach ( $existing_file_paths as $existing_file_path ) {
494
495 $needs_update = false;
496 $new_value = array();
497 $value = maybe_unserialize( trim( $existing_file_path->meta_value ) );
498
499 if ( $value ) {
500 foreach ( $value as $key => $file ) {
501 if ( ! is_array( $file ) ) {
502 $needs_update = true;
503 $new_value[ $key ] = array(
504 'file' => $file,
505 'name' => wc_get_filename_from_url( $file ),
506 );
507 } else {
508 $new_value[ $key ] = $file;
509 }
510 }
511 if ( $needs_update ) {
512 // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.serialize_serialize
513 $new_value = serialize( $new_value );
514
515 $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 ) );
516 }
517 }
518 }
519 }
520 }
521
522 /**
523 * Update DB version for 2.1
524 *
525 * @return void
526 */
527 function wc_update_210_db_version() {
528 WC_Install::update_db_version( '2.1.0' );
529 }
530
531 /**
532 * Update shipping options for 2.2
533 *
534 * @return void
535 */
536 function wc_update_220_shipping() {
537 $woocommerce_ship_to_destination = 'shipping';
538
539 if ( get_option( 'woocommerce_ship_to_billing_address_only' ) === 'yes' ) {
540 $woocommerce_ship_to_destination = 'billing_only';
541 } elseif ( get_option( 'woocommerce_ship_to_billing' ) === 'yes' ) {
542 $woocommerce_ship_to_destination = 'billing';
543 }
544
545 add_option( 'woocommerce_ship_to_destination', $woocommerce_ship_to_destination, '', 'no' );
546 }
547
548 /**
549 * Update order statuses for 2.2
550 *
551 * @return void
552 */
553 function wc_update_220_order_status() {
554 global $wpdb;
555 $wpdb->query(
556 "UPDATE {$wpdb->posts} as posts
557 LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_id
558 LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )
559 LEFT JOIN {$wpdb->terms} AS term USING( term_id )
560 SET posts.post_status = 'wc-pending'
561 WHERE posts.post_type = 'shop_order'
562 AND posts.post_status = 'publish'
563 AND tax.taxonomy = 'shop_order_status'
564 AND term.slug LIKE 'pending%';"
565 );
566 $wpdb->query(
567 "UPDATE {$wpdb->posts} as posts
568 LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_id
569 LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )
570 LEFT JOIN {$wpdb->terms} AS term USING( term_id )
571 SET posts.post_status = 'wc-processing'
572 WHERE posts.post_type = 'shop_order'
573 AND posts.post_status = 'publish'
574 AND tax.taxonomy = 'shop_order_status'
575 AND term.slug LIKE 'processing%';"
576 );
577 $wpdb->query(
578 "UPDATE {$wpdb->posts} as posts
579 LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_id
580 LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )
581 LEFT JOIN {$wpdb->terms} AS term USING( term_id )
582 SET posts.post_status = 'wc-on-hold'
583 WHERE posts.post_type = 'shop_order'
584 AND posts.post_status = 'publish'
585 AND tax.taxonomy = 'shop_order_status'
586 AND term.slug LIKE 'on-hold%';"
587 );
588 $wpdb->query(
589 "UPDATE {$wpdb->posts} as posts
590 LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_id
591 LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )
592 LEFT JOIN {$wpdb->terms} AS term USING( term_id )
593 SET posts.post_status = 'wc-completed'
594 WHERE posts.post_type = 'shop_order'
595 AND posts.post_status = 'publish'
596 AND tax.taxonomy = 'shop_order_status'
597 AND term.slug LIKE 'completed%';"
598 );
599 $wpdb->query(
600 "UPDATE {$wpdb->posts} as posts
601 LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_id
602 LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )
603 LEFT JOIN {$wpdb->terms} AS term USING( term_id )
604 SET posts.post_status = 'wc-cancelled'
605 WHERE posts.post_type = 'shop_order'
606 AND posts.post_status = 'publish'
607 AND tax.taxonomy = 'shop_order_status'
608 AND term.slug LIKE 'cancelled%';"
609 );
610 $wpdb->query(
611 "UPDATE {$wpdb->posts} as posts
612 LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_id
613 LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )
614 LEFT JOIN {$wpdb->terms} AS term USING( term_id )
615 SET posts.post_status = 'wc-refunded'
616 WHERE posts.post_type = 'shop_order'
617 AND posts.post_status = 'publish'
618 AND tax.taxonomy = 'shop_order_status'
619 AND term.slug LIKE 'refunded%';"
620 );
621 $wpdb->query(
622 "UPDATE {$wpdb->posts} as posts
623 LEFT JOIN {$wpdb->term_relationships} AS rel ON posts.ID = rel.object_id
624 LEFT JOIN {$wpdb->term_taxonomy} AS tax USING( term_taxonomy_id )
625 LEFT JOIN {$wpdb->terms} AS term USING( term_id )
626 SET posts.post_status = 'wc-failed'
627 WHERE posts.post_type = 'shop_order'
628 AND posts.post_status = 'publish'
629 AND tax.taxonomy = 'shop_order_status'
630 AND term.slug LIKE 'failed%';"
631 );
632 }
633
634 /**
635 * Update variations for 2.2
636 *
637 * @return void
638 */
639 function wc_update_220_variations() {
640 global $wpdb;
641 // Update variations which manage stock.
642 $update_variations = $wpdb->get_results(
643 "SELECT DISTINCT posts.ID AS variation_id, posts.post_parent AS variation_parent FROM {$wpdb->posts} as posts
644 LEFT OUTER JOIN {$wpdb->postmeta} AS postmeta ON posts.ID = postmeta.post_id AND postmeta.meta_key = '_stock'
645 LEFT OUTER JOIN {$wpdb->postmeta} as postmeta2 ON posts.ID = postmeta2.post_id AND postmeta2.meta_key = '_manage_stock'
646 WHERE posts.post_type = 'product_variation'
647 AND postmeta.meta_value IS NOT NULL
648 AND postmeta.meta_value != ''
649 AND postmeta2.meta_value IS NULL"
650 );
651
652 foreach ( $update_variations as $variation ) {
653 $parent_backorders = get_post_meta( $variation->variation_parent, '_backorders', true );
654 add_post_meta( $variation->variation_id, '_manage_stock', 'yes', true );
655 add_post_meta( $variation->variation_id, '_backorders', $parent_backorders ? $parent_backorders : 'no', true );
656 }
657 }
658
659 /**
660 * Update attributes for 2.2
661 *
662 * @return void
663 */
664 function wc_update_220_attributes() {
665 global $wpdb;
666 // Update taxonomy names with correct sanitized names.
667 $attribute_taxonomies = $wpdb->get_results( 'SELECT attribute_name, attribute_id FROM ' . $wpdb->prefix . 'woocommerce_attribute_taxonomies' );
668
669 foreach ( $attribute_taxonomies as $attribute_taxonomy ) {
670 $sanitized_attribute_name = wc_sanitize_taxonomy_name( $attribute_taxonomy->attribute_name );
671 if ( $sanitized_attribute_name !== $attribute_taxonomy->attribute_name ) {
672 if ( ! $wpdb->get_var( $wpdb->prepare( "SELECT 1=1 FROM {$wpdb->prefix}woocommerce_attribute_taxonomies WHERE attribute_name = %s;", $sanitized_attribute_name ) ) ) {
673 // Update attribute.
674 $wpdb->update(
675 "{$wpdb->prefix}woocommerce_attribute_taxonomies",
676 array(
677 'attribute_name' => $sanitized_attribute_name,
678 ),
679 array(
680 'attribute_id' => $attribute_taxonomy->attribute_id,
681 )
682 );
683
684 // Update terms.
685 $wpdb->update(
686 $wpdb->term_taxonomy,
687 array( 'taxonomy' => wc_attribute_taxonomy_name( $sanitized_attribute_name ) ),
688 array( 'taxonomy' => 'pa_' . $attribute_taxonomy->attribute_name )
689 );
690 }
691 }
692 }
693
694 delete_transient( 'wc_attribute_taxonomies' );
695 WC_Cache_Helper::invalidate_cache_group( 'woocommerce-attributes' );
696 }
697
698 /**
699 * Update DB version for 2.2
700 *
701 * @return void
702 */
703 function wc_update_220_db_version() {
704 WC_Install::update_db_version( '2.2.0' );
705 }
706
707 /**
708 * Update options for 2.3
709 *
710 * @return void
711 */
712 function wc_update_230_options() {
713 // _money_spent and _order_count may be out of sync - clear them
714 delete_metadata( 'user', 0, '_money_spent', '', true );
715 delete_metadata( 'user', 0, '_order_count', '', true );
716 delete_metadata( 'user', 0, '_last_order', '', true );
717
718 // 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.
719 if ( '' === get_option( 'woocommerce_default_customer_address', false ) && wc_prices_include_tax() ) {
720 update_option( 'woocommerce_default_customer_address', 'base' );
721 }
722 }
723
724 /**
725 * Update DB version for 2.3
726 *
727 * @return void
728 */
729 function wc_update_230_db_version() {
730 WC_Install::update_db_version( '2.3.0' );
731 }
732
733 /**
734 * Update calc discount options for 2.4
735 *
736 * @return void
737 */
738 function wc_update_240_options() {
739 /**
740 * Coupon discount calculations.
741 * Maintain the old coupon logic for upgrades.
742 */
743 update_option( 'woocommerce_calc_discounts_sequentially', 'yes' );
744 }
745
746 /**
747 * Update shipping methods for 2.4
748 *
749 * @return void
750 */
751 function wc_update_240_shipping_methods() {
752 /**
753 * Flat Rate Shipping.
754 * Update legacy options to new math based options.
755 */
756 $shipping_methods = array(
757 'woocommerce_flat_rates' => new WC_Shipping_Legacy_Flat_Rate(),
758 'woocommerce_international_delivery_flat_rates' => new WC_Shipping_Legacy_International_Delivery(),
759 );
760 foreach ( $shipping_methods as $flat_rate_option_key => $shipping_method ) {
761 // Stop this running more than once if routine is repeated.
762 if ( version_compare( $shipping_method->get_option( 'version', 0 ), '2.4.0', '<' ) ) {
763 $shipping_classes = WC()->shipping()->get_shipping_classes();
764 $has_classes = count( $shipping_classes ) > 0;
765 $cost_key = $has_classes ? 'no_class_cost' : 'cost';
766 $min_fee = $shipping_method->get_option( 'minimum_fee' );
767 $math_cost_strings = array(
768 'cost' => array(),
769 'no_class_cost' => array(),
770 );
771
772 $math_cost_strings[ $cost_key ][] = $shipping_method->get_option( 'cost' );
773 $fee = $shipping_method->get_option( 'fee' );
774
775 if ( $fee ) {
776 $math_cost_strings[ $cost_key ][] = strstr( $fee, '%' ) ? '[fee percent="' . str_replace( '%', '', $fee ) . '" min="' . esc_attr( $min_fee ) . '"]' : $fee;
777 }
778
779 foreach ( $shipping_classes as $shipping_class ) {
780 $rate_key = 'class_cost_' . $shipping_class->slug;
781 $math_cost_strings[ $rate_key ] = $math_cost_strings['no_class_cost'];
782 }
783
784 $flat_rates = array_filter( (array) get_option( $flat_rate_option_key, array() ) );
785
786 if ( $flat_rates ) {
787 foreach ( $flat_rates as $shipping_class => $rate ) {
788 $rate_key = 'class_cost_' . $shipping_class;
789 if ( $rate['cost'] || $rate['fee'] ) {
790 $math_cost_strings[ $rate_key ][] = $rate['cost'];
791 $math_cost_strings[ $rate_key ][] = strstr( $rate['fee'], '%' ) ? '[fee percent="' . str_replace( '%', '', $rate['fee'] ) . '" min="' . esc_attr( $min_fee ) . '"]' : $rate['fee'];
792 }
793 }
794 }
795
796 if ( 'item' === $shipping_method->type ) {
797 foreach ( $math_cost_strings as $key => $math_cost_string ) {
798 $math_cost_strings[ $key ] = array_filter( array_map( 'trim', $math_cost_strings[ $key ] ) );
799 if ( ! empty( $math_cost_strings[ $key ] ) ) {
800 $last_key = max( 0, count( $math_cost_strings[ $key ] ) - 1 );
801 $math_cost_strings[ $key ][0] = '( ' . $math_cost_strings[ $key ][0];
802 $math_cost_strings[ $key ][ $last_key ] .= ' ) * [qty]';
803 }
804 }
805 }
806
807 $math_cost_strings['cost'][] = $shipping_method->get_option( 'cost_per_order' );
808
809 // Save settings.
810 foreach ( $math_cost_strings as $option_id => $math_cost_string ) {
811 $shipping_method->settings[ $option_id ] = implode( ' + ', array_filter( $math_cost_string ) );
812 }
813
814 $shipping_method->settings['version'] = '2.4.0';
815 $shipping_method->settings['type'] = 'item' === $shipping_method->settings['type'] ? 'class' : $shipping_method->settings['type'];
816
817 update_option( $shipping_method->plugin_id . $shipping_method->id . '_settings', $shipping_method->settings );
818 }
819 }
820 }
821
822 /**
823 * Update API keys for 2.4
824 *
825 * @return void
826 */
827 function wc_update_240_api_keys() {
828 global $wpdb;
829 /**
830 * Update the old user API keys to the new Apps keys.
831 */
832 $api_users = $wpdb->get_results( "SELECT user_id FROM $wpdb->usermeta WHERE meta_key = 'woocommerce_api_consumer_key'" );
833 $apps_keys = array();
834
835 // Get user data.
836 foreach ( $api_users as $_user ) {
837 $user = get_userdata( $_user->user_id );
838 $apps_keys[] = array(
839 'user_id' => $user->ID,
840 'permissions' => $user->woocommerce_api_key_permissions,
841 'consumer_key' => wc_api_hash( $user->woocommerce_api_consumer_key ),
842 'consumer_secret' => $user->woocommerce_api_consumer_secret,
843 'truncated_key' => substr( $user->woocommerce_api_consumer_secret, -7 ),
844 );
845 }
846
847 if ( ! empty( $apps_keys ) ) {
848 // Create new apps.
849 foreach ( $apps_keys as $app ) {
850 $wpdb->insert(
851 $wpdb->prefix . 'woocommerce_api_keys',
852 $app,
853 array(
854 '%d',
855 '%s',
856 '%s',
857 '%s',
858 '%s',
859 )
860 );
861 }
862
863 // Delete old user keys from usermeta.
864 foreach ( $api_users as $_user ) {
865 $user_id = intval( $_user->user_id );
866 delete_user_meta( $user_id, 'woocommerce_api_consumer_key' );
867 delete_user_meta( $user_id, 'woocommerce_api_consumer_secret' );
868 delete_user_meta( $user_id, 'woocommerce_api_key_permissions' );
869 }
870 }
871 }
872
873 /**
874 * Update webhooks for 2.4
875 *
876 * @return void
877 */
878 function wc_update_240_webhooks() {
879 // phpcs:disable WordPress.DB.SlowDBQuery
880
881 /**
882 * Webhooks.
883 * Make sure order.update webhooks get the woocommerce_order_edit_status hook.
884 */
885 $order_update_webhooks = get_posts(
886 array(
887 'posts_per_page' => -1,
888 'post_type' => 'shop_webhook',
889 'meta_key' => '_topic',
890 'meta_value' => 'order.updated',
891 )
892 );
893 foreach ( $order_update_webhooks as $order_update_webhook ) {
894 $webhook = new WC_Webhook( $order_update_webhook->ID );
895 $webhook->set_topic( 'order.updated' );
896 }
897
898 // phpcs:enable WordPress.DB.SlowDBQuery
899 }
900
901 /**
902 * Update refunds for 2.4
903 *
904 * @return void
905 */
906 function wc_update_240_refunds() {
907 global $wpdb;
908 /**
909 * Refunds for full refunded orders.
910 * Update fully refunded orders to ensure they have a refund line item so reports add up.
911 */
912 $refunded_orders = get_posts(
913 array(
914 'posts_per_page' => -1,
915 'post_type' => 'shop_order',
916 'post_status' => array( 'wc-refunded' ),
917 )
918 );
919
920 // Ensure emails are disabled during this update routine.
921 remove_all_actions( 'woocommerce_order_status_refunded_notification' );
922 remove_all_actions( 'woocommerce_order_partially_refunded_notification' );
923 remove_action( 'woocommerce_order_status_refunded', array( 'WC_Emails', 'send_transactional_email' ) );
924 remove_action( 'woocommerce_order_partially_refunded', array( 'WC_Emails', 'send_transactional_email' ) );
925
926 foreach ( $refunded_orders as $refunded_order ) {
927 $order_total = get_post_meta( $refunded_order->ID, '_order_total', true );
928 $refunded_total = $wpdb->get_var(
929 $wpdb->prepare(
930 "SELECT SUM( postmeta.meta_value )
931 FROM $wpdb->postmeta AS postmeta
932 INNER JOIN $wpdb->posts AS posts ON ( posts.post_type = 'shop_order_refund' AND posts.post_parent = %d )
933 WHERE postmeta.meta_key = '_refund_amount'
934 AND postmeta.post_id = posts.ID",
935 $refunded_order->ID
936 )
937 );
938
939 if ( $order_total > $refunded_total ) {
940 wc_create_refund(
941 array(
942 'amount' => $order_total - $refunded_total,
943 'reason' => __( 'Order fully refunded', 'woocommerce' ),
944 'order_id' => $refunded_order->ID,
945 'line_items' => array(),
946 'date' => $refunded_order->post_modified,
947 )
948 );
949 }
950 }
951
952 wc_delete_shop_order_transients();
953 }
954
955 /**
956 * Update DB version for 2.4
957 *
958 * @return void
959 */
960 function wc_update_240_db_version() {
961 WC_Install::update_db_version( '2.4.0' );
962 }
963
964 /**
965 * Update variations for 2.4.1
966 *
967 * @return void
968 */
969 function wc_update_241_variations() {
970 global $wpdb;
971
972 // Select variations that don't have any _stock_status implemented on WooCommerce 2.2.
973 $update_variations = $wpdb->get_results(
974 "SELECT DISTINCT posts.ID AS variation_id, posts.post_parent AS variation_parent
975 FROM {$wpdb->posts} as posts
976 LEFT OUTER JOIN {$wpdb->postmeta} AS postmeta ON posts.ID = postmeta.post_id AND postmeta.meta_key = '_stock_status'
977 WHERE posts.post_type = 'product_variation'
978 AND postmeta.meta_value IS NULL"
979 );
980
981 foreach ( $update_variations as $variation ) {
982 // Get the parent _stock_status.
983 $parent_stock_status = get_post_meta( $variation->variation_parent, '_stock_status', true );
984
985 // Set the _stock_status.
986 add_post_meta( $variation->variation_id, '_stock_status', $parent_stock_status ? $parent_stock_status : 'instock', true );
987
988 // Delete old product children array.
989 delete_transient( 'wc_product_children_' . $variation->variation_parent );
990 }
991
992 // Invalidate old transients such as wc_var_price.
993 WC_Cache_Helper::get_transient_version( 'product', true );
994 }
995
996 /**
997 * Update DB version for 2.4.1
998 *
999 * @return void
1000 */
1001 function wc_update_241_db_version() {
1002 WC_Install::update_db_version( '2.4.1' );
1003 }
1004
1005 /**
1006 * Update currency settings for 2.5
1007 *
1008 * @return void
1009 */
1010 function wc_update_250_currency() {
1011 global $wpdb;
1012 // Fix currency settings for LAK currency.
1013 $current_currency = get_option( 'woocommerce_currency' );
1014
1015 if ( 'KIP' === $current_currency ) {
1016 update_option( 'woocommerce_currency', 'LAK' );
1017 }
1018
1019 // phpcs:disable WordPress.DB.SlowDBQuery
1020
1021 // Update LAK currency code.
1022 $wpdb->update(
1023 $wpdb->postmeta,
1024 array(
1025 'meta_value' => 'LAK',
1026 ),
1027 array(
1028 'meta_key' => '_order_currency',
1029 'meta_value' => 'KIP',
1030 )
1031 );
1032
1033 // phpcs:enable WordPress.DB.SlowDBQuery
1034 }
1035
1036 /**
1037 * Update DB version for 2.5
1038 *
1039 * @return void
1040 */
1041 function wc_update_250_db_version() {
1042 WC_Install::update_db_version( '2.5.0' );
1043 }
1044
1045 /**
1046 * Update ship to countries options for 2.6
1047 *
1048 * @return void
1049 */
1050 function wc_update_260_options() {
1051 // woocommerce_calc_shipping option has been removed in 2.6.
1052 if ( 'no' === get_option( 'woocommerce_calc_shipping' ) ) {
1053 update_option( 'woocommerce_ship_to_countries', 'disabled' );
1054 }
1055
1056 WC_Admin_Notices::add_notice( 'legacy_shipping' );
1057 }
1058
1059 /**
1060 * Update term meta for 2.6
1061 *
1062 * @return void
1063 */
1064 function wc_update_260_termmeta() {
1065 global $wpdb;
1066 /**
1067 * Migrate term meta to WordPress tables.
1068 */
1069 if ( get_option( 'db_version' ) >= 34370 && $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->prefix}woocommerce_termmeta';" ) ) {
1070 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;" ) ) {
1071 $wpdb->query( "DROP TABLE IF EXISTS {$wpdb->prefix}woocommerce_termmeta" );
1072 wp_cache_flush();
1073 }
1074 }
1075 }
1076
1077 /**
1078 * Update zones for 2.6
1079 *
1080 * @return void
1081 */
1082 function wc_update_260_zones() {
1083 global $wpdb;
1084 /**
1085 * Old (table rate) shipping zones to new core shipping zones migration.
1086 * zone_enabled and zone_type are no longer used, but it's safe to leave them be.
1087 */
1088 if ( $wpdb->get_var( "SHOW COLUMNS FROM `{$wpdb->prefix}woocommerce_shipping_zones` LIKE 'zone_enabled';" ) ) {
1089 $wpdb->query( "ALTER TABLE {$wpdb->prefix}woocommerce_shipping_zones CHANGE `zone_type` `zone_type` VARCHAR(40) NOT NULL DEFAULT '';" );
1090 $wpdb->query( "ALTER TABLE {$wpdb->prefix}woocommerce_shipping_zones CHANGE `zone_enabled` `zone_enabled` INT(1) NOT NULL DEFAULT 1;" );
1091 }
1092 }
1093
1094 /**
1095 * Update zone methods for 2.6
1096 *
1097 * @return void
1098 */
1099 function wc_update_260_zone_methods() {
1100 global $wpdb;
1101
1102 /**
1103 * Shipping zones in WC 2.6.0 use a table named woocommerce_shipping_zone_methods.
1104 * 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).
1105 */
1106 if ( $wpdb->get_var( "SHOW TABLES LIKE '{$wpdb->prefix}woocommerce_shipping_zone_shipping_methods';" ) ) {
1107 $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;" );
1108
1109 if ( $old_methods ) {
1110 $max_new_id = $wpdb->get_var( "SELECT MAX(instance_id) FROM {$wpdb->prefix}woocommerce_shipping_zone_methods" );
1111 $max_old_id = $wpdb->get_var( "SELECT MAX(shipping_method_id) FROM {$wpdb->prefix}woocommerce_shipping_zone_shipping_methods" );
1112
1113 // Avoid ID conflicts.
1114 $wpdb->query( $wpdb->prepare( "ALTER TABLE {$wpdb->prefix}woocommerce_shipping_zone_methods AUTO_INCREMENT = %d;", max( $max_new_id, $max_old_id ) + 1 ) );
1115
1116 // Store changes.
1117 $changes = array();
1118
1119 // Move data.
1120 foreach ( $old_methods as $old_method ) {
1121 $wpdb->insert(
1122 $wpdb->prefix . 'woocommerce_shipping_zone_methods',
1123 array(
1124 'zone_id' => $old_method->zone_id,
1125 'method_id' => $old_method->shipping_method_type,
1126 'method_order' => $old_method->shipping_method_order,
1127 )
1128 );
1129
1130 $new_instance_id = $wpdb->insert_id;
1131
1132 // Move main settings.
1133 $older_settings_key = 'woocommerce_' . $old_method->shipping_method_type . '-' . $old_method->shipping_method_id . '_settings';
1134 $old_settings_key = 'woocommerce_' . $old_method->shipping_method_type . '_' . $old_method->shipping_method_id . '_settings';
1135 add_option( 'woocommerce_' . $old_method->shipping_method_type . '_' . $new_instance_id . '_settings', get_option( $old_settings_key, get_option( $older_settings_key ) ) );
1136
1137 // Handling for table rate and flat rate box shipping.
1138 if ( 'table_rate' === $old_method->shipping_method_type ) {
1139 // Move priority settings.
1140 add_option( 'woocommerce_table_rate_default_priority_' . $new_instance_id, get_option( 'woocommerce_table_rate_default_priority_' . $old_method->shipping_method_id ) );
1141 add_option( 'woocommerce_table_rate_priorities_' . $new_instance_id, get_option( 'woocommerce_table_rate_priorities_' . $old_method->shipping_method_id ) );
1142
1143 // Move rates.
1144 $wpdb->update(
1145 $wpdb->prefix . 'woocommerce_shipping_table_rates',
1146 array(
1147 'shipping_method_id' => $new_instance_id,
1148 ),
1149 array(
1150 'shipping_method_id' => $old_method->shipping_method_id,
1151 )
1152 );
1153 } elseif ( 'flat_rate_boxes' === $old_method->shipping_method_type ) {
1154 $wpdb->update(
1155 $wpdb->prefix . 'woocommerce_shipping_flat_rate_boxes',
1156 array(
1157 'shipping_method_id' => $new_instance_id,
1158 ),
1159 array(
1160 'shipping_method_id' => $old_method->shipping_method_id,
1161 )
1162 );
1163 }
1164
1165 $changes[ $old_method->shipping_method_id ] = $new_instance_id;
1166 }
1167
1168 // $changes contains keys (old method ids) and values (new instance ids) if extra processing is needed in plugins.
1169 // Store this to an option so extensions can pick it up later, then fire an action.
1170 update_option( 'woocommerce_updated_instance_ids', $changes );
1171 do_action( 'woocommerce_updated_instance_ids', $changes );
1172 }
1173 }
1174
1175 // Change ranges used to ...
1176 $wpdb->query( "UPDATE {$wpdb->prefix}woocommerce_shipping_zone_locations SET location_code = REPLACE( location_code, '-', '...' );" );
1177 }
1178
1179 /**
1180 * Update refunds for 2.6
1181 *
1182 * @return void
1183 */
1184 function wc_update_260_refunds() {
1185 global $wpdb;
1186 /**
1187 * Refund item qty should be negative.
1188 */
1189 $wpdb->query(
1190 "UPDATE {$wpdb->prefix}woocommerce_order_itemmeta as item_meta
1191 LEFT JOIN {$wpdb->prefix}woocommerce_order_items as items ON item_meta.order_item_id = items.order_item_id
1192 LEFT JOIN {$wpdb->posts} as posts ON items.order_id = posts.ID
1193 SET item_meta.meta_value = item_meta.meta_value * -1
1194 WHERE item_meta.meta_value > 0 AND item_meta.meta_key = '_qty' AND posts.post_type = 'shop_order_refund'"
1195 );
1196 }
1197
1198 /**
1199 * Update DB version for 2.6
1200 *
1201 * @return void
1202 */
1203 function wc_update_260_db_version() {
1204 WC_Install::update_db_version( '2.6.0' );
1205 }
1206
1207 /**
1208 * Update webhooks for 3.0
1209 *
1210 * @return void
1211 */
1212 function wc_update_300_webhooks() {
1213 // phpcs:disable WordPress.DB.SlowDBQuery
1214
1215 /**
1216 * Make sure product.update webhooks get the woocommerce_product_quick_edit_save
1217 * and woocommerce_product_bulk_edit_save hooks.
1218 */
1219 $product_update_webhooks = get_posts(
1220 array(
1221 'posts_per_page' => -1,
1222 'post_type' => 'shop_webhook',
1223 'meta_key' => '_topic',
1224 'meta_value' => 'product.updated',
1225 )
1226 );
1227 foreach ( $product_update_webhooks as $product_update_webhook ) {
1228 $webhook = new WC_Webhook( $product_update_webhook->ID );
1229 $webhook->set_topic( 'product.updated' );
1230 }
1231
1232 // phpcs:enable WordPress.DB.SlowDBQuery
1233 }
1234
1235 /**
1236 * Add an index to the field comment_type to improve the response time of the query
1237 * used by WC_Comments::wp_count_comments() to get the number of comments by type.
1238 */
1239 function wc_update_300_comment_type_index() {
1240 global $wpdb;
1241
1242 $index_exists = $wpdb->get_row( "SHOW INDEX FROM {$wpdb->comments} WHERE column_name = 'comment_type' and key_name = 'woo_idx_comment_type'" );
1243
1244 if ( is_null( $index_exists ) ) {
1245 // Add an index to the field comment_type to improve the response time of the query
1246 // used by WC_Comments::wp_count_comments() to get the number of comments by type.
1247 $wpdb->query( "ALTER TABLE {$wpdb->comments} ADD INDEX woo_idx_comment_type (comment_type)" );
1248 }
1249 }
1250
1251 /**
1252 * Update grouped products for 3.0
1253 *
1254 * @return void
1255 */
1256 function wc_update_300_grouped_products() {
1257 global $wpdb;
1258 $parents = $wpdb->get_col( "SELECT DISTINCT( post_parent ) FROM {$wpdb->posts} WHERE post_parent > 0 AND post_type = 'product';" );
1259 foreach ( $parents as $parent_id ) {
1260 $parent = wc_get_product( $parent_id );
1261 if ( $parent && $parent->is_type( 'grouped' ) ) {
1262 $children_ids = get_posts(
1263 array(
1264 'post_parent' => $parent_id,
1265 'posts_per_page' => -1,
1266 'post_type' => 'product',
1267 'fields' => 'ids',
1268 )
1269 );
1270 update_post_meta( $parent_id, '_children', $children_ids );
1271
1272 // Update children to remove the parent.
1273 $wpdb->update(
1274 $wpdb->posts,
1275 array(
1276 'post_parent' => 0,
1277 ),
1278 array(
1279 'post_parent' => $parent_id,
1280 )
1281 );
1282 }
1283 }
1284 }
1285
1286 /**
1287 * Update shipping tax classes for 3.0
1288 *
1289 * @return void
1290 */
1291 function wc_update_300_settings() {
1292 $woocommerce_shipping_tax_class = get_option( 'woocommerce_shipping_tax_class' );
1293 if ( '' === $woocommerce_shipping_tax_class ) {
1294 update_option( 'woocommerce_shipping_tax_class', 'inherit' );
1295 } elseif ( 'standard' === $woocommerce_shipping_tax_class ) {
1296 update_option( 'woocommerce_shipping_tax_class', '' );
1297 }
1298 }
1299
1300 /**
1301 * Convert meta values into term for product visibility.
1302 */
1303 function wc_update_300_product_visibility() {
1304 global $wpdb;
1305
1306 WC_Install::create_terms();
1307
1308 $featured_term = get_term_by( 'name', 'featured', 'product_visibility' );
1309
1310 if ( $featured_term ) {
1311 $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 ) );
1312 }
1313
1314 $exclude_search_term = get_term_by( 'name', 'exclude-from-search', 'product_visibility' );
1315
1316 if ( $exclude_search_term ) {
1317 $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 ) );
1318 }
1319
1320 $exclude_catalog_term = get_term_by( 'name', 'exclude-from-catalog', 'product_visibility' );
1321
1322 if ( $exclude_catalog_term ) {
1323 $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 ) );
1324 }
1325
1326 $outofstock_term = get_term_by( 'name', 'outofstock', 'product_visibility' );
1327
1328 if ( $outofstock_term ) {
1329 $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 ) );
1330 }
1331
1332 $rating_term = get_term_by( 'name', 'rated-1', 'product_visibility' );
1333
1334 if ( $rating_term ) {
1335 $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 ) );
1336 }
1337
1338 $rating_term = get_term_by( 'name', 'rated-2', 'product_visibility' );
1339
1340 if ( $rating_term ) {
1341 $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 ) );
1342 }
1343
1344 $rating_term = get_term_by( 'name', 'rated-3', 'product_visibility' );
1345
1346 if ( $rating_term ) {
1347 $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO {$wpdb->term_relationships} SELECT post_id, %d, 0 FROM {$wpdb->postmeta} WHERE meta_key = '_wc_average_rating' AND ROUND( meta_value ) = 3;", $rating_term->term_taxonomy_id ) );
1348 }
1349
1350 $rating_term = get_term_by( 'name', 'rated-4', 'product_visibility' );
1351
1352 if ( $rating_term ) {
1353 $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO {$wpdb->term_relationships} SELECT post_id, %d, 0 FROM {$wpdb->postmeta} WHERE meta_key = '_wc_average_rating' AND ROUND( meta_value ) = 4;", $rating_term->term_taxonomy_id ) );
1354 }
1355
1356 $rating_term = get_term_by( 'name', 'rated-5', 'product_visibility' );
1357
1358 if ( $rating_term ) {
1359 $wpdb->query( $wpdb->prepare( "INSERT IGNORE INTO {$wpdb->term_relationships} SELECT post_id, %d, 0 FROM {$wpdb->postmeta} WHERE meta_key = '_wc_average_rating' AND ROUND( meta_value ) = 5;", $rating_term->term_taxonomy_id ) );
1360 }
1361 }
1362
1363 /**
1364 * Update DB Version.
1365 */
1366 function wc_update_300_db_version() {
1367 WC_Install::update_db_version( '3.0.0' );
1368 }
1369
1370 /**
1371 * Add an index to the downloadable product permissions table to improve performance of update_user_by_order_id.
1372 */
1373 function wc_update_310_downloadable_products() {
1374 global $wpdb;
1375
1376 $index_exists = $wpdb->get_row( "SHOW INDEX FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE column_name = 'order_id' and key_name = 'order_id'" );
1377
1378 if ( is_null( $index_exists ) ) {
1379 $wpdb->query( "ALTER TABLE {$wpdb->prefix}woocommerce_downloadable_product_permissions ADD INDEX order_id (order_id)" );
1380 }
1381 }
1382
1383 /**
1384 * Find old order notes and ensure they have the correct type for exclusion.
1385 */
1386 function wc_update_310_old_comments() {
1387 global $wpdb;
1388
1389 $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 = '';" );
1390 }
1391
1392 /**
1393 * Update DB Version.
1394 */
1395 function wc_update_310_db_version() {
1396 WC_Install::update_db_version( '3.1.0' );
1397 }
1398
1399 /**
1400 * Update shop_manager capabilities.
1401 */
1402 function wc_update_312_shop_manager_capabilities() {
1403 $role = get_role( 'shop_manager' );
1404 $role->remove_cap( 'unfiltered_html' );
1405 }
1406
1407 /**
1408 * Update DB Version.
1409 */
1410 function wc_update_312_db_version() {
1411 WC_Install::update_db_version( '3.1.2' );
1412 }
1413
1414 /**
1415 * Update state codes for Mexico.
1416 */
1417 function wc_update_320_mexican_states() {
1418 global $wpdb;
1419
1420 $mx_states = array(
1421 'Distrito Federal' => 'CMX',
1422 'Jalisco' => 'JAL',
1423 'Nuevo Leon' => 'NLE',
1424 'Aguascalientes' => 'AGS',
1425 'Baja California' => 'BCN',
1426 'Baja California Sur' => 'BCS',
1427 'Campeche' => 'CAM',
1428 'Chiapas' => 'CHP',
1429 'Chihuahua' => 'CHH',
1430 'Coahuila' => 'COA',
1431 'Colima' => 'COL',
1432 'Durango' => 'DGO',
1433 'Guanajuato' => 'GTO',
1434 'Guerrero' => 'GRO',
1435 'Hidalgo' => 'HGO',
1436 'Estado de Mexico' => 'MEX',
1437 'Michoacan' => 'MIC',
1438 'Morelos' => 'MOR',
1439 'Nayarit' => 'NAY',
1440 'Oaxaca' => 'OAX',
1441 'Puebla' => 'PUE',
1442 'Queretaro' => 'QRO',
1443 'Quintana Roo' => 'ROO',
1444 'San Luis Potosi' => 'SLP',
1445 'Sinaloa' => 'SIN',
1446 'Sonora' => 'SON',
1447 'Tabasco' => 'TAB',
1448 'Tamaulipas' => 'TMP',
1449 'Tlaxcala' => 'TLA',
1450 'Veracruz' => 'VER',
1451 'Yucatan' => 'YUC',
1452 'Zacatecas' => 'ZAC',
1453 );
1454
1455 foreach ( $mx_states as $old => $new ) {
1456 $wpdb->query(
1457 $wpdb->prepare(
1458 "UPDATE $wpdb->postmeta
1459 SET meta_value = %s
1460 WHERE meta_key IN ( '_billing_state', '_shipping_state' )
1461 AND meta_value = %s",
1462 $new,
1463 $old
1464 )
1465 );
1466 $wpdb->update(
1467 "{$wpdb->prefix}woocommerce_shipping_zone_locations",
1468 array(
1469 'location_code' => 'MX:' . $new,
1470 ),
1471 array(
1472 'location_code' => 'MX:' . $old,
1473 )
1474 );
1475 $wpdb->update(
1476 "{$wpdb->prefix}woocommerce_tax_rates",
1477 array(
1478 'tax_rate_state' => strtoupper( $new ),
1479 ),
1480 array(
1481 'tax_rate_state' => strtoupper( $old ),
1482 )
1483 );
1484 }
1485 }
1486
1487 /**
1488 * Update DB Version.
1489 */
1490 function wc_update_320_db_version() {
1491 WC_Install::update_db_version( '3.2.0' );
1492 }
1493
1494 /**
1495 * Update image settings to use new aspect ratios and widths.
1496 */
1497 function wc_update_330_image_options() {
1498 $old_thumbnail_size = get_option( 'shop_catalog_image_size', array() );
1499 $old_single_size = get_option( 'shop_single_image_size', array() );
1500
1501 if ( ! empty( $old_thumbnail_size['width'] ) ) {
1502 $width = absint( $old_thumbnail_size['width'] );
1503 $height = absint( $old_thumbnail_size['height'] );
1504 $hard_crop = ! empty( $old_thumbnail_size['crop'] );
1505
1506 if ( ! $width ) {
1507 $width = 300;
1508 }
1509
1510 if ( ! $height ) {
1511 $height = $width;
1512 }
1513
1514 update_option( 'woocommerce_thumbnail_image_width', $width );
1515
1516 // Calculate cropping mode from old image options.
1517 if ( ! $hard_crop ) {
1518 update_option( 'woocommerce_thumbnail_cropping', 'uncropped' );
1519 } elseif ( $width === $height ) {
1520 update_option( 'woocommerce_thumbnail_cropping', '1:1' );
1521 } else {
1522 $ratio = $width / $height;
1523 $fraction = wc_decimal_to_fraction( $ratio );
1524
1525 if ( $fraction ) {
1526 update_option( 'woocommerce_thumbnail_cropping', 'custom' );
1527 update_option( 'woocommerce_thumbnail_cropping_custom_width', $fraction[0] );
1528 update_option( 'woocommerce_thumbnail_cropping_custom_height', $fraction[1] );
1529 }
1530 }
1531 }
1532
1533 // Single is uncropped.
1534 if ( ! empty( $old_single_size['width'] ) ) {
1535 update_option( 'woocommerce_single_image_width', absint( $old_single_size['width'] ) );
1536 }
1537 }
1538
1539 /**
1540 * Migrate webhooks from post type to CRUD.
1541 */
1542 function wc_update_330_webhooks() {
1543 register_post_type( 'shop_webhook' );
1544
1545 // Map statuses from post_type to Webhooks CRUD.
1546 $statuses = array(
1547 'publish' => 'active',
1548 'draft' => 'paused',
1549 'pending' => 'disabled',
1550 );
1551
1552 $posts = get_posts(
1553 array(
1554 'posts_per_page' => -1,
1555 'post_type' => 'shop_webhook',
1556 'post_status' => 'any',
1557 )
1558 );
1559
1560 foreach ( $posts as $post ) {
1561 $webhook = new WC_Webhook();
1562 $webhook->set_name( $post->post_title );
1563 $webhook->set_status( isset( $statuses[ $post->post_status ] ) ? $statuses[ $post->post_status ] : 'disabled' );
1564 $webhook->set_delivery_url( get_post_meta( $post->ID, '_delivery_url', true ) );
1565 $webhook->set_secret( get_post_meta( $post->ID, '_secret', true ) );
1566 $webhook->set_topic( get_post_meta( $post->ID, '_topic', true ) );
1567 $webhook->set_api_version( get_post_meta( $post->ID, '_api_version', true ) );
1568 $webhook->set_user_id( $post->post_author );
1569 $webhook->set_pending_delivery( false );
1570 $webhook->save();
1571
1572 wp_delete_post( $post->ID, true );
1573 }
1574
1575 unregister_post_type( 'shop_webhook' );
1576 }
1577
1578 /**
1579 * Assign default cat to all products with no cats.
1580 */
1581 function wc_update_330_set_default_product_cat() {
1582 /*
1583 * When a product category is deleted, we need to check
1584 * if the product has no categories assigned. Then assign
1585 * it a default category.
1586 */
1587 wc_get_container()->get( AssignDefaultCategory::class )->maybe_assign_default_product_cat();
1588 }
1589
1590 /**
1591 * Update product stock status to use the new onbackorder status.
1592 */
1593 function wc_update_330_product_stock_status() {
1594 global $wpdb;
1595
1596 if ( 'yes' !== get_option( 'woocommerce_manage_stock' ) ) {
1597 return;
1598 }
1599
1600 $min_stock_amount = (int) get_option( 'woocommerce_notify_no_stock_amount', 0 );
1601
1602 // Get all products that have stock management enabled, stock less than or equal to min stock amount, and backorders enabled.
1603 $post_ids = $wpdb->get_col(
1604 $wpdb->prepare(
1605 "SELECT t1.post_id FROM $wpdb->postmeta t1
1606 INNER JOIN $wpdb->postmeta t2
1607 ON t1.post_id = t2.post_id
1608 AND t1.meta_key = '_manage_stock' AND t1.meta_value = 'yes'
1609 AND t2.meta_key = '_stock' AND t2.meta_value <= %d
1610 INNER JOIN $wpdb->postmeta t3
1611 ON t2.post_id = t3.post_id
1612 AND t3.meta_key = '_backorders' AND ( t3.meta_value = 'yes' OR t3.meta_value = 'notify' )",
1613 $min_stock_amount
1614 )
1615 );
1616
1617 if ( empty( $post_ids ) ) {
1618 return;
1619 }
1620
1621 $post_ids = array_map( 'absint', $post_ids );
1622
1623 // phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
1624 // Set the status to onbackorder for those products.
1625 $wpdb->query(
1626 "UPDATE $wpdb->postmeta
1627 SET meta_value = 'onbackorder'
1628 WHERE meta_key = '_stock_status' AND post_id IN ( " . implode( ',', $post_ids ) . ' )'
1629 );
1630 // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
1631 }
1632
1633 /**
1634 * Clear addons page transients
1635 */
1636 function wc_update_330_clear_transients() {
1637 delete_transient( 'wc_addons_sections' );
1638 delete_transient( 'wc_addons_featured' );
1639 }
1640
1641 /**
1642 * Set PayPal's sandbox credentials.
1643 */
1644 function wc_update_330_set_paypal_sandbox_credentials() {
1645
1646 $paypal_settings = get_option( 'woocommerce_paypal_settings' );
1647
1648 if ( isset( $paypal_settings['testmode'] ) && 'yes' === $paypal_settings['testmode'] ) {
1649 foreach ( array( 'api_username', 'api_password', 'api_signature' ) as $credential ) {
1650 if ( ! empty( $paypal_settings[ $credential ] ) ) {
1651 $paypal_settings[ 'sandbox_' . $credential ] = $paypal_settings[ $credential ];
1652 }
1653 }
1654
1655 update_option( 'woocommerce_paypal_settings', $paypal_settings );
1656 }
1657 }
1658
1659 /**
1660 * Update DB Version.
1661 */
1662 function wc_update_330_db_version() {
1663 WC_Install::update_db_version( '3.3.0' );
1664 }
1665
1666 /**
1667 * Update state codes for Ireland and BD.
1668 */
1669 function wc_update_340_states() {
1670 $country_states = array(
1671 'IE' => array(
1672 'CK' => 'CO',
1673 'DN' => 'D',
1674 'GY' => 'G',
1675 'TY' => 'TA',
1676 ),
1677 'BD' => array(
1678 'BAG' => 'BD-05',
1679 'BAN' => 'BD-01',
1680 'BAR' => 'BD-02',
1681 'BARI' => 'BD-06',
1682 'BHO' => 'BD-07',
1683 'BOG' => 'BD-03',
1684 'BRA' => 'BD-04',
1685 'CHA' => 'BD-09',
1686 'CHI' => 'BD-10',
1687 'CHU' => 'BD-12',
1688 'COX' => 'BD-11',
1689 'COM' => 'BD-08',
1690 'DHA' => 'BD-13',
1691 'DIN' => 'BD-14',
1692 'FAR' => 'BD-15',
1693 'FEN' => 'BD-16',
1694 'GAI' => 'BD-19',
1695 'GAZI' => 'BD-18',
1696 'GOP' => 'BD-17',
1697 'HAB' => 'BD-20',
1698 'JAM' => 'BD-21',
1699 'JES' => 'BD-22',
1700 'JHA' => 'BD-25',
1701 'JHE' => 'BD-23',
1702 'JOY' => 'BD-24',
1703 'KHA' => 'BD-29',
1704 'KHU' => 'BD-27',
1705 'KIS' => 'BD-26',
1706 'KUR' => 'BD-28',
1707 'KUS' => 'BD-30',
1708 'LAK' => 'BD-31',
1709 'LAL' => 'BD-32',
1710 'MAD' => 'BD-36',
1711 'MAG' => 'BD-37',
1712 'MAN' => 'BD-33',
1713 'MEH' => 'BD-39',
1714 'MOU' => 'BD-38',
1715 'MUN' => 'BD-35',
1716 'MYM' => 'BD-34',
1717 'NAO' => 'BD-48',
1718 'NAR' => 'BD-43',
1719 'NARG' => 'BD-40',
1720 'NARD' => 'BD-42',
1721 'NAT' => 'BD-44',
1722 'NAW' => 'BD-45',
1723 'NET' => 'BD-41',
1724 'NIL' => 'BD-46',
1725 'NOA' => 'BD-47',
1726 'PAB' => 'BD-49',
1727 'PAN' => 'BD-52',
1728 'PAT' => 'BD-51',
1729 'PIR' => 'BD-50',
1730 'RAJB' => 'BD-53',
1731 'RAJ' => 'BD-54',
1732 'RAN' => 'BD-56',
1733 'RANP' => 'BD-55',
1734 'SAT' => 'BD-58',
1735 'SHA' => 'BD-57',
1736 'SIR' => 'BD-59',
1737 'SUN' => 'BD-61',
1738 'SYL' => 'BD-60',
1739 'TAN' => 'BD-63',
1740 'THA' => 'BD-64',
1741 ),
1742 );
1743
1744 update_option( 'woocommerce_update_340_states', $country_states );
1745 }
1746
1747 /**
1748 * Update next state in the queue.
1749 *
1750 * @return bool True to run again, false if completed.
1751 */
1752 function wc_update_340_state() {
1753 global $wpdb;
1754
1755 $country_states = array_filter( (array) get_option( 'woocommerce_update_340_states', array() ) );
1756
1757 if ( empty( $country_states ) ) {
1758 return false;
1759 }
1760
1761 foreach ( $country_states as $country => $states ) {
1762 foreach ( $states as $old => $new ) {
1763 $wpdb->query(
1764 $wpdb->prepare(
1765 "UPDATE $wpdb->postmeta
1766 SET meta_value = %s
1767 WHERE meta_key IN ( '_billing_state', '_shipping_state' )
1768 AND meta_value = %s",
1769 $new,
1770 $old
1771 )
1772 );
1773 $wpdb->update(
1774 "{$wpdb->prefix}woocommerce_shipping_zone_locations",
1775 array(
1776 'location_code' => $country . ':' . $new,
1777 ),
1778 array(
1779 'location_code' => $country . ':' . $old,
1780 )
1781 );
1782 $wpdb->update(
1783 "{$wpdb->prefix}woocommerce_tax_rates",
1784 array(
1785 'tax_rate_state' => strtoupper( $new ),
1786 ),
1787 array(
1788 'tax_rate_state' => strtoupper( $old ),
1789 )
1790 );
1791 unset( $country_states[ $country ][ $old ] );
1792
1793 if ( empty( $country_states[ $country ] ) ) {
1794 unset( $country_states[ $country ] );
1795 }
1796 break 2;
1797 }
1798 }
1799
1800 if ( ! empty( $country_states ) ) {
1801 return update_option( 'woocommerce_update_340_states', $country_states );
1802 }
1803
1804 delete_option( 'woocommerce_update_340_states' );
1805
1806 return false;
1807 }
1808
1809 /**
1810 * Set last active prop for users.
1811 */
1812 function wc_update_340_last_active() {
1813 global $wpdb;
1814 // @codingStandardsIgnoreStart.
1815 $wpdb->query(
1816 $wpdb->prepare( "
1817 INSERT INTO {$wpdb->usermeta} (user_id, meta_key, meta_value)
1818 SELECT DISTINCT users.ID, 'wc_last_active', %s
1819 FROM {$wpdb->users} as users
1820 LEFT OUTER JOIN {$wpdb->usermeta} AS usermeta ON users.ID = usermeta.user_id AND usermeta.meta_key = 'wc_last_active'
1821 WHERE usermeta.meta_value IS NULL
1822 ",
1823 (string) strtotime( date( 'Y-m-d', current_time( 'timestamp', true ) ) )
1824 )
1825 );
1826 // @codingStandardsIgnoreEnd.
1827 }
1828
1829 /**
1830 * Update DB Version.
1831 */
1832 function wc_update_340_db_version() {
1833 WC_Install::update_db_version( '3.4.0' );
1834 }
1835
1836 /**
1837 * Remove duplicate foreign keys
1838 *
1839 * @return void
1840 */
1841 function wc_update_343_cleanup_foreign_keys() {
1842 global $wpdb;
1843
1844 $results = $wpdb->get_results(
1845 "SELECT CONSTRAINT_NAME
1846 FROM information_schema.TABLE_CONSTRAINTS
1847 WHERE CONSTRAINT_SCHEMA = '{$wpdb->dbname}'
1848 AND CONSTRAINT_NAME LIKE '%wc_download_log_ib%'
1849 AND CONSTRAINT_TYPE = 'FOREIGN KEY'
1850 AND TABLE_NAME = '{$wpdb->prefix}wc_download_log'"
1851 );
1852
1853 if ( $results ) {
1854 foreach ( $results as $fk ) {
1855 $wpdb->query( "ALTER TABLE {$wpdb->prefix}wc_download_log DROP FOREIGN KEY {$fk->CONSTRAINT_NAME}" ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
1856 }
1857 }
1858 }
1859
1860 /**
1861 * Update DB version.
1862 *
1863 * @return void
1864 */
1865 function wc_update_343_db_version() {
1866 WC_Install::update_db_version( '3.4.3' );
1867 }
1868
1869 /**
1870 * Recreate user roles so existing users will get the new capabilities.
1871 *
1872 * @return void
1873 */
1874 function wc_update_344_recreate_roles() {
1875 WC_Install::remove_roles();
1876 WC_Install::create_roles();
1877 }
1878
1879 /**
1880 * Update DB version.
1881 *
1882 * @return void
1883 */
1884 function wc_update_344_db_version() {
1885 WC_Install::update_db_version( '3.4.4' );
1886 }
1887
1888 /**
1889 * Set the comment type to 'review' for product reviews that don't have a comment type.
1890 */
1891 function wc_update_350_reviews_comment_type() {
1892 global $wpdb;
1893
1894 $wpdb->query(
1895 "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 = ''"
1896 );
1897 }
1898
1899 /**
1900 * Update DB Version.
1901 */
1902 function wc_update_350_db_version() {
1903 WC_Install::update_db_version( '3.5.0' );
1904 }
1905
1906 /**
1907 * Drop the fk_wc_download_log_permission_id FK as we use a new one with the table and blog prefix for MS compatability.
1908 *
1909 * @return void
1910 */
1911 function wc_update_352_drop_download_log_fk() {
1912 global $wpdb;
1913 $results = $wpdb->get_results(
1914 "SELECT CONSTRAINT_NAME
1915 FROM information_schema.TABLE_CONSTRAINTS
1916 WHERE CONSTRAINT_SCHEMA = '{$wpdb->dbname}'
1917 AND CONSTRAINT_NAME = 'fk_wc_download_log_permission_id'
1918 AND CONSTRAINT_TYPE = 'FOREIGN KEY'
1919 AND TABLE_NAME = '{$wpdb->prefix}wc_download_log'"
1920 );
1921
1922 // We only need to drop the old key as WC_Install::create_tables() takes care of creating the new FK.
1923 if ( $results ) {
1924 $wpdb->query( "ALTER TABLE {$wpdb->prefix}wc_download_log DROP FOREIGN KEY fk_wc_download_log_permission_id" ); // phpcs:ignore WordPress.WP.PreparedSQL.NotPrepared
1925 }
1926 }
1927
1928 /**
1929 * Remove edit_user capabilities from shop managers and use "translated" capabilities instead.
1930 * See wc_shop_manager_has_capability function.
1931 */
1932 function wc_update_354_modify_shop_manager_caps() {
1933 global $wp_roles;
1934
1935 if ( ! class_exists( 'WP_Roles' ) ) {
1936 return;
1937 }
1938
1939 if ( ! isset( $wp_roles ) ) {
1940 $wp_roles = new WP_Roles(); // @codingStandardsIgnoreLine
1941 }
1942
1943 $wp_roles->remove_cap( 'shop_manager', 'edit_users' );
1944 }
1945
1946 /**
1947 * Update DB Version.
1948 */
1949 function wc_update_354_db_version() {
1950 WC_Install::update_db_version( '3.5.4' );
1951 }
1952
1953 /**
1954 * Update product lookup tables in bulk.
1955 */
1956 function wc_update_360_product_lookup_tables() {
1957 wc_update_product_lookup_tables();
1958 }
1959
1960 /**
1961 * Renames ordering meta to be consistent across taxonomies.
1962 */
1963 function wc_update_360_term_meta() {
1964 global $wpdb;
1965
1966 $wpdb->query( "UPDATE {$wpdb->termmeta} SET meta_key = 'order' WHERE meta_key LIKE 'order_pa_%';" );
1967 }
1968
1969 /**
1970 * Add new user_order_remaining_expires to speed up user download permission fetching.
1971 *
1972 * @return void
1973 */
1974 function wc_update_360_downloadable_product_permissions_index() {
1975 global $wpdb;
1976
1977 $index_exists = $wpdb->get_row( "SHOW INDEX FROM {$wpdb->prefix}woocommerce_downloadable_product_permissions WHERE key_name = 'user_order_remaining_expires'" );
1978
1979 if ( is_null( $index_exists ) ) {
1980 $wpdb->query( "ALTER TABLE {$wpdb->prefix}woocommerce_downloadable_product_permissions ADD INDEX user_order_remaining_expires (user_id,order_id,downloads_remaining,access_expires)" );
1981 }
1982 }
1983
1984 /**
1985 * Update DB Version.
1986 */
1987 function wc_update_360_db_version() {
1988 WC_Install::update_db_version( '3.6.0' );
1989 }
1990
1991 /**
1992 * Put tax classes into a DB table.
1993 *
1994 * @return void
1995 */
1996 function wc_update_370_tax_rate_classes() {
1997 global $wpdb;
1998
1999 $classes = array_map( 'trim', explode( "\n", get_option( 'woocommerce_tax_classes' ) ) );
2000
2001 if ( $classes ) {
2002 foreach ( $classes as $class ) {
2003 if ( empty( $class ) ) {
2004 continue;
2005 }
2006 WC_Tax::create_tax_class( $class );
2007 }
2008 }
2009 delete_option( 'woocommerce_tax_classes' );
2010 }
2011
2012 /**
2013 * Update currency settings for 3.7.0
2014 *
2015 * @return void
2016 */
2017 function wc_update_370_mro_std_currency() {
2018 global $wpdb;
2019
2020 // Fix currency settings for MRU and STN currency.
2021 $current_currency = get_option( 'woocommerce_currency' );
2022
2023 if ( 'MRO' === $current_currency ) {
2024 update_option( 'woocommerce_currency', 'MRU' );
2025 }
2026
2027 if ( 'STD' === $current_currency ) {
2028 update_option( 'woocommerce_currency', 'STN' );
2029 }
2030
2031 // Update MRU currency code.
2032 $wpdb->update(
2033 $wpdb->postmeta,
2034 array(
2035 'meta_value' => 'MRU', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
2036 ),
2037 array(
2038 'meta_key' => '_order_currency', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
2039 'meta_value' => 'MRO', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
2040 )
2041 );
2042
2043 // Update STN currency code.
2044 $wpdb->update(
2045 $wpdb->postmeta,
2046 array(
2047 'meta_value' => 'STN', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
2048 ),
2049 array(
2050 'meta_key' => '_order_currency', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
2051 'meta_value' => 'STD', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
2052 )
2053 );
2054 }
2055
2056 /**
2057 * Update DB Version.
2058 */
2059 function wc_update_370_db_version() {
2060 WC_Install::update_db_version( '3.7.0' );
2061 }
2062
2063 /**
2064 * We've moved the MaxMind database to a new location, as per the TOS' requirement that the database not
2065 * be publicly accessible.
2066 */
2067 function wc_update_390_move_maxmind_database() {
2068 // Make sure to use all of the correct filters to pull the local database path.
2069 $old_path = apply_filters( 'woocommerce_geolocation_local_database_path', WP_CONTENT_DIR . '/uploads/GeoLite2-Country.mmdb', 2 );
2070
2071 // Generate a prefix for the old file and store it in the integration as it would expect it.
2072 $prefix = wp_generate_password( 32, false );
2073 update_option( 'woocommerce_maxmind_geolocation_settings', array( 'database_prefix' => $prefix ) );
2074
2075 // Generate the new path in the same way that the integration will.
2076 $uploads_dir = wp_upload_dir();
2077 $new_path = trailingslashit( $uploads_dir['basedir'] ) . 'woocommerce_uploads/' . $prefix . '-GeoLite2-Country.mmdb';
2078 $new_path = apply_filters( 'woocommerce_geolocation_local_database_path', $new_path, 2 );
2079 $new_path = apply_filters( 'woocommerce_maxmind_geolocation_database_path', $new_path );
2080
2081 // phpcs:ignore WordPress.PHP.NoSilencedErrors.Discouraged
2082 @rename( $old_path, $new_path );
2083 }
2084
2085 /**
2086 * So that we can best meet MaxMind's TOS, the geolocation database update cron should run once per 15 days.
2087 */
2088 function wc_update_390_change_geolocation_database_update_cron() {
2089 wp_clear_scheduled_hook( 'woocommerce_geoip_updater' );
2090 wp_schedule_event( time() + ( DAY_IN_SECONDS * 15 ), 'fifteendays', 'woocommerce_geoip_updater' );
2091 }
2092
2093 /**
2094 * Update DB version.
2095 */
2096 function wc_update_390_db_version() {
2097 WC_Install::update_db_version( '3.9.0' );
2098 }
2099
2100 /**
2101 * Increase column size
2102 */
2103 function wc_update_400_increase_size_of_column() {
2104 global $wpdb;
2105 $wpdb->query( "ALTER TABLE {$wpdb->prefix}wc_product_meta_lookup MODIFY COLUMN `min_price` decimal(19,4) NULL default NULL" );
2106 $wpdb->query( "ALTER TABLE {$wpdb->prefix}wc_product_meta_lookup MODIFY COLUMN `max_price` decimal(19,4) NULL default NULL" );
2107 }
2108
2109 /**
2110 * Reset ActionScheduler migration status. Needs AS >= 3.0 shipped with WC >= 4.0.
2111 */
2112 function wc_update_400_reset_action_scheduler_migration_status() {
2113 if (
2114 class_exists( 'ActionScheduler_DataController' ) &&
2115 method_exists( 'ActionScheduler_DataController', 'mark_migration_incomplete' )
2116 ) {
2117 \ActionScheduler_DataController::mark_migration_incomplete();
2118 }
2119 }
2120
2121 /**
2122 * Update DB version.
2123 */
2124 function wc_update_400_db_version() {
2125 WC_Install::update_db_version( '4.0.0' );
2126 }
2127
2128 /**
2129 * Register attributes as terms for variable products, in increments of 100 products.
2130 *
2131 * This migration was added to support a new mechanism to improve the filtering of
2132 * variable products by attribute (https://github.com/woocommerce/woocommerce/pull/26260),
2133 * however that mechanism was later reverted (https://github.com/woocommerce/woocommerce/pull/27625)
2134 * due to numerous issues found. Thus the migration is no longer needed.
2135 *
2136 * @return bool true if the migration needs to be run again.
2137 */
2138 function wc_update_440_insert_attribute_terms_for_variable_products() {
2139 return false;
2140 }
2141
2142 /**
2143 * Update DB version.
2144 */
2145 function wc_update_440_db_version() {
2146 WC_Install::update_db_version( '4.4.0' );
2147 }
2148
2149 /**
2150 * Update DB version to 4.5.0.
2151 */
2152 function wc_update_450_db_version() {
2153 WC_Install::update_db_version( '4.5.0' );
2154 }
2155
2156 /**
2157 * Sanitize all coupons code.
2158 *
2159 * @return bool True to run again, false if completed.
2160 */
2161 function wc_update_450_sanitize_coupons_code() {
2162 global $wpdb;
2163
2164 $coupon_id = 0;
2165 $last_coupon_id = get_option( 'woocommerce_update_450_last_coupon_id', '0' );
2166
2167 $coupons = $wpdb->get_results(
2168 $wpdb->prepare(
2169 "SELECT ID, post_title FROM $wpdb->posts WHERE ID > %d AND post_type = 'shop_coupon' LIMIT 10",
2170 $last_coupon_id
2171 ),
2172 ARRAY_A
2173 );
2174
2175 if ( empty( $coupons ) ) {
2176 delete_option( 'woocommerce_update_450_last_coupon_id' );
2177 return false;
2178 }
2179
2180 foreach ( $coupons as $key => $data ) {
2181 $coupon_id = intval( $data['ID'] );
2182 $code = trim( wp_filter_kses( $data['post_title'] ) );
2183
2184 if ( ! empty( $code ) && $data['post_title'] !== $code ) {
2185 $wpdb->update(
2186 $wpdb->posts,
2187 array(
2188 'post_title' => $code,
2189 ),
2190 array(
2191 'ID' => $coupon_id,
2192 ),
2193 array(
2194 '%s',
2195 ),
2196 array(
2197 '%d',
2198 )
2199 );
2200
2201 // Clean cache.
2202 clean_post_cache( $coupon_id );
2203 wp_cache_delete( WC_Cache_Helper::get_cache_prefix( 'coupons' ) . 'coupon_id_from_code_' . $data['post_title'], 'coupons' );
2204 }
2205 }
2206
2207 // Start the run again.
2208 if ( $coupon_id ) {
2209 return update_option( 'woocommerce_update_450_last_coupon_id', $coupon_id );
2210 }
2211
2212 delete_option( 'woocommerce_update_450_last_coupon_id' );
2213 return false;
2214 }
2215
2216 /**
2217 * Fixes product review count that might have been incorrect.
2218 *
2219 * See @link https://github.com/woocommerce/woocommerce/issues/27688.
2220 */
2221 function wc_update_500_fix_product_review_count() {
2222 global $wpdb;
2223
2224 $product_id = 0;
2225 $last_product_id = get_option( 'woocommerce_update_500_last_product_id', '0' );
2226
2227 $products_data = $wpdb->get_results(
2228 $wpdb->prepare(
2229 "
2230 SELECT post_id, meta_value
2231 FROM $wpdb->postmeta
2232 JOIN $wpdb->posts
2233 ON $wpdb->postmeta.post_id = $wpdb->posts.ID
2234 WHERE
2235 post_type = 'product'
2236 AND post_status = 'publish'
2237 AND post_id > %d
2238 AND meta_key = '_wc_review_count'
2239 ORDER BY post_id ASC
2240 LIMIT 10
2241 ",
2242 $last_product_id
2243 ),
2244 ARRAY_A
2245 );
2246
2247 if ( empty( $products_data ) ) {
2248 delete_option( 'woocommerce_update_500_last_product_id' );
2249 return false;
2250 }
2251
2252 $product_ids_to_check = array_column( $products_data, 'post_id' );
2253 $actual_review_counts = WC_Comments::get_review_counts_for_product_ids( $product_ids_to_check );
2254
2255 foreach ( $products_data as $product_data ) {
2256 $product_id = intval( $product_data['post_id'] );
2257 $current_review_count = intval( $product_data['meta_value'] );
2258
2259 if ( intval( $actual_review_counts[ $product_id ] ) !== $current_review_count ) {
2260 WC_Comments::clear_transients( $product_id );
2261 }
2262 }
2263
2264 // Start the run again.
2265 if ( $product_id ) {
2266 return update_option( 'woocommerce_update_500_last_product_id', $product_id );
2267 }
2268
2269 delete_option( 'woocommerce_update_500_last_product_id' );
2270 return false;
2271 }
2272
2273 /**
2274 * Update DB version to 5.0.0.
2275 */
2276 function wc_update_500_db_version() {
2277 WC_Install::update_db_version( '5.0.0' );
2278 }
2279
2280 /**
2281 * Creates the refund and returns policy page.
2282 *
2283 * See @link https://github.com/woocommerce/woocommerce/issues/29235.
2284 */
2285 function wc_update_560_create_refund_returns_page() {
2286 /**
2287 * Filter on the pages created to return what we expect.
2288 *
2289 * @param array $pages The default WC pages.
2290 */
2291 function filter_created_pages( $pages ) {
2292 $page_to_create = array( 'refund_returns' );
2293
2294 return array_intersect_key( $pages, array_flip( $page_to_create ) );
2295 }
2296
2297 add_filter( 'woocommerce_create_pages', 'filter_created_pages' );
2298
2299 WC_Install::create_pages();
2300
2301 remove_filter( 'woocommerce_create_pages', 'filter_created_pages' );
2302 }
2303
2304 /**
2305 * Update DB version to 5.6.0.
2306 */
2307 function wc_update_560_db_version() {
2308 WC_Install::update_db_version( '5.6.0' );
2309 }
2310
2311 /**
2312 * Migrate rate limit options to the new table.
2313 *
2314 * See @link https://github.com/woocommerce/woocommerce/issues/27103.
2315 */
2316 function wc_update_600_migrate_rate_limit_options() {
2317 global $wpdb;
2318
2319 $rate_limits = $wpdb->get_results(
2320 "
2321 SELECT option_name, option_value
2322 FROM $wpdb->options
2323 WHERE option_name LIKE 'woocommerce_rate_limit_add_payment_method_%'
2324 ",
2325 ARRAY_A
2326 );
2327 $prefix_length = strlen( 'woocommerce_rate_limit_' );
2328
2329 foreach ( $rate_limits as $rate_limit ) {
2330 $new_delay = (int) $rate_limit['option_value'] - time();
2331
2332 // Migrate the limit if it hasn't expired yet.
2333 if ( 0 < $new_delay ) {
2334 $action_id = substr( $rate_limit['option_name'], $prefix_length );
2335 WC_Rate_Limiter::set_rate_limit( $action_id, $new_delay );
2336 }
2337
2338 delete_option( $rate_limit['option_name'] );
2339 }
2340 }
2341
2342 /**
2343 * Update DB version to 6.0.0.
2344 */
2345 function wc_update_600_db_version() {
2346 WC_Install::update_db_version( '6.0.0' );
2347 }
2348
2349 /**
2350 * Create the product attributes lookup table and initiate its filling,
2351 * unless the table had been already created manually (via the tools page).
2352 *
2353 * @return false Always false, since the LookupDataStore class handles all the data filling process.
2354 */
2355 function wc_update_630_create_product_attributes_lookup_table() {
2356 $data_store = wc_get_container()->get( LookupDataStore::class );
2357 $data_regenerator = wc_get_container()->get( DataRegenerator::class );
2358
2359 /**
2360 * If the table exists and contains data, it was manually created by user before the migration ran.
2361 * 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).
2362 */
2363 if ( ! $data_store->check_lookup_table_exists() || ( ! $data_store->lookup_table_has_data() && ! $data_store->regeneration_is_in_progress() ) ) {
2364 $data_regenerator->initiate_regeneration();
2365 }
2366
2367 return false;
2368 }
2369
2370 /**
2371 *
2372 * Update DB version to 6.3.0.
2373 */
2374 function wc_update_630_db_version() {
2375 WC_Install::update_db_version( '6.3.0' );
2376 }
2377
2378 /**
2379 * Create the primary key for the product attributes lookup table if it doesn't exist already.
2380 *
2381 * @return bool Always false.
2382 */
2383 function wc_update_640_add_primary_key_to_product_attributes_lookup_table() {
2384 wc_get_container()->get( DataRegenerator::class )->create_table_primary_index();
2385
2386 return false;
2387 }
2388
2389 /**
2390 *
2391 * Update DB version to 6.4.0.
2392 */
2393 function wc_update_640_db_version() {
2394 WC_Install::update_db_version( '6.4.0' );
2395 }
2396
2397 /**
2398 * Add the standard WooCommerce upload directories to the Approved Product Download Directories list
2399 * and start populating it based on existing product download URLs, but do not enable the feature
2400 * (for existing installations, a site admin should review and make a conscious decision to enable).
2401 */
2402 function wc_update_650_approved_download_directories() {
2403 $directory_sync = wc_get_container()->get( Download_Directories_Sync::class );
2404 $directory_sync->init_hooks();
2405 $directory_sync->init_feature( true, false );
2406 }
2407
2408 /**
2409 * In some cases, the approved download directories table may not have been successfully created during the update to
2410 * 6.5.0. If this was the case we will need to re-initialize the feature.
2411 */
2412 function wc_update_651_approved_download_directories() {
2413 global $wpdb;
2414
2415 $download_directories = wc_get_container()->get( Download_Directories::class );
2416 $directory_sync = wc_get_container()->get( Download_Directories_Sync::class );
2417
2418 // Check if at least 1 row exists, without scanning the entire table.
2419 $is_populated = (bool) $wpdb->get_var(
2420 'SELECT 1 FROM ' . $download_directories->get_table() . ' LIMIT 1'
2421 );
2422
2423 // If the table contains rules (or does not yet, but a sync is in-progress) we should do nothing else at this point.
2424 if ( $is_populated || $directory_sync->in_progress() ) {
2425 return;
2426 }
2427
2428 // Otherwise, it seems reasonable to assume that the feature was not initialized as expected during the update to
2429 // 6.5.0. Let's give that another try.
2430 $directory_sync->init_hooks();
2431 $directory_sync->init_feature( true, false );
2432 }
2433
2434 /**
2435 * Purges the comments count cache after 6.7.0 split reviews from the comments page.
2436 */
2437 function wc_update_670_purge_comments_count_cache() {
2438 if ( ! is_callable( 'WC_Comments::delete_comments_count_cache' ) ) {
2439 return;
2440 }
2441
2442 WC_Comments::delete_comments_count_cache();
2443 }
2444