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