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