diff --git a/assets/js/frontend/address-i18n.js b/assets/js/frontend/address-i18n.js index 04167773568..d50c149cd74 100644 --- a/assets/js/frontend/address-i18n.js +++ b/assets/js/frontend/address-i18n.js @@ -1,132 +1,128 @@ /*global wc_address_i18n_params */ jQuery( function( $ ) { - // wc_address_i18n_params is required to continue, ensure the object exists - if ( typeof wc_address_i18n_params === 'undefined' ) { - return false; + // wc_address_i18n_params is required to continue, ensure the object exists + if ( typeof wc_address_i18n_params === 'undefined' ) { + return false; + } + + var locale_json = wc_address_i18n_params.locale.replace( /"/g, '"' ), locale = $.parseJSON( locale_json ); + + function field_is_required( field, is_required ) { + if ( is_required ) { + field.find( 'label .optional' ).remove(); + field.addClass( 'validate-required' ); + + if ( field.find( 'label .required' ).length === 0 ) { + field.find( 'label' ).append( ' *' ); + } + } else { + field.find( 'label .required' ).remove(); + field.removeClass( 'validate-required' ); + + if ( field.find( 'label .optional' ).length === 0 ) { + field.find( 'label' ).append( ' (' + wc_address_i18n_params.i18n_optional_text + ')' ); + } + } + } + + // Handle locale + $( document.body ).bind( 'country_to_state_changing', function( event, country, wrapper ) { + var thisform = wrapper, thislocale; + + if ( typeof locale[ country ] !== 'undefined' ) { + thislocale = locale[ country ]; + } else { + thislocale = locale['default']; } - var locale_json = wc_address_i18n_params.locale.replace( /"/g, '"' ), - locale = $.parseJSON( locale_json ); + var $postcodefield = thisform.find( '#billing_postcode_field, #shipping_postcode_field' ), + $cityfield = thisform.find( '#billing_city_field, #shipping_city_field' ), + $statefield = thisform.find( '#billing_state_field, #shipping_state_field' ); - function field_is_required( field, is_required ) { - if ( is_required ) { - field.find( 'label .optional' ).remove(); - field.addClass( 'validate-required' ); + if ( ! $postcodefield.attr( 'data-o_class' ) ) { + $postcodefield.attr( 'data-o_class', $postcodefield.attr( 'class' ) ); + $cityfield.attr( 'data-o_class', $cityfield.attr( 'class' ) ); + $statefield.attr( 'data-o_class', $statefield.attr( 'class' ) ); + } - if ( field.find( 'label .required' ).length === 0 ) { - field.find( 'label' ).append( ' *' ); - } - } else { - field.find( 'label .required' ).remove(); - field.removeClass( 'validate-required' ); + var locale_fields = $.parseJSON( wc_address_i18n_params.locale_fields ); - if ( field.find( 'label .optional' ).length === 0 ) { - field.find( 'label' ).append( ' (' + wc_address_i18n_params.i18n_optional_text + ')' ); - } - } + $.each( locale_fields, function( key, value ) { + + var field = thisform.find( value ), + fieldLocale = $.extend( true, {}, locale['default'][ key ], thislocale[ key ] ); + + // Labels. + if ( typeof fieldLocale.label !== 'undefined' ) { + field.find( 'label' ).html( fieldLocale.label ); } - $( document.body ) + // Placeholders. + if ( typeof fieldLocale.placeholder !== 'undefined' ) { + field.find( 'input' ).attr( 'placeholder', fieldLocale.placeholder ); + field.find( '.select2-selection__placeholder' ).text( fieldLocale.placeholder ); + } - // Handle locale - .bind( 'country_to_state_changing', function( event, country, wrapper ) { + // Use the i18n label as a placeholder if there is no label element and no i18n placeholder. + if ( typeof fieldLocale.placeholder === 'undefined' && typeof fieldLocale.label !== 'undefined' && ! field.find( 'label' ).length ) { + field.find( 'input' ).attr( 'placeholder', fieldLocale.label ); + field.find( '.select2-selection__placeholder' ).text( fieldLocale.label ); + } - var thisform = wrapper, thislocale; + // Required. + if ( typeof fieldLocale.required !== 'undefined' ) { + field_is_required( field, fieldLocale.required ); + } else { + field_is_required( field, false ); + } - if ( typeof locale[ country ] !== 'undefined' ) { - thislocale = locale[ country ]; + // Priority. + if ( typeof fieldLocale.priority !== 'undefined' ) { + field.data( 'priority', fieldLocale.priority ); + } + + // Hidden fields. + if ( 'state' !== key ) { + if ( typeof fieldLocale.hidden !== 'undefined' && true === fieldLocale.hidden ) { + field.hide().find( 'input' ).val( '' ); } else { - thislocale = locale['default']; + field.show(); } + } + }); - var $postcodefield = thisform.find( '#billing_postcode_field, #shipping_postcode_field' ), - $cityfield = thisform.find( '#billing_city_field, #shipping_city_field' ), - $statefield = thisform.find( '#billing_state_field, #shipping_state_field' ); + var fieldsets = $('.woocommerce-billing-fields__field-wrapper, .woocommerce-shipping-fields__field-wrapper, .woocommerce-address-fields__field-wrapper, .woocommerce-additional-fields__field-wrapper .woocommerce-account-fields'); - if ( ! $postcodefield.attr( 'data-o_class' ) ) { - $postcodefield.attr( 'data-o_class', $postcodefield.attr( 'class' ) ); - $cityfield.attr( 'data-o_class', $cityfield.attr( 'class' ) ); - $statefield.attr( 'data-o_class', $statefield.attr( 'class' ) ); + fieldsets.each( function( index, fieldset ) { + var rows = $( fieldset ).find( '.form-row' ); + var wrapper = rows.first().parent(); + + // Before sorting, ensure all fields have a priority for bW compatibility. + var last_priority = 0; + + rows.each( function() { + if ( ! $( this ).data( 'priority' ) ) { + $( this ).data( 'priority', last_priority + 1 ); } + last_priority = $( this ).data( 'priority' ); + } ); - var locale_fields = $.parseJSON( wc_address_i18n_params.locale_fields ); + // Sort the fields. + rows.sort( function( a, b ) { + var asort = $( a ).data( 'priority' ), + bsort = $( b ).data( 'priority' ); - $.each( locale_fields, function( key, value ) { - - var field = thisform.find( value ), - fieldLocale = $.extend( true, {}, locale['default'][ key ], thislocale[ key ] ); - - // Labels. - if ( typeof fieldLocale.label !== 'undefined' ) { - field.find( 'label' ).html( fieldLocale.label ); - } - - // Placeholders. - if ( typeof fieldLocale.placeholder !== 'undefined' ) { - field.find( 'input' ).attr( 'placeholder', fieldLocale.placeholder ); - field.find( '.select2-selection__placeholder' ).text( fieldLocale.placeholder ); - } - - // Use the i18n label as a placeholder if there is no label element and no i18n placeholder. - if ( typeof fieldLocale.placeholder === 'undefined' && typeof fieldLocale.label !== 'undefined' && ! field.find( 'label' ).length ) { - field.find( 'input' ).attr( 'placeholder', fieldLocale.label ); - field.find( '.select2-selection__placeholder' ).text( fieldLocale.label ); - } - - // Required. - if ( typeof fieldLocale.required !== 'undefined' ) { - field_is_required( field, fieldLocale.required ); - } else { - field_is_required( field, false ); - } - - // Priority. - if ( typeof fieldLocale.priority !== 'undefined' ) { - field.data( 'priority', fieldLocale.priority ); - } - - // Hidden fields. - if ( 'state' !== key ) { - if ( typeof fieldLocale.hidden !== 'undefined' && true === fieldLocale.hidden ) { - field.hide().find( 'input' ).val( '' ); - } else { - field.show(); - } - } - }); - - var fieldsets = $('.woocommerce-billing-fields__field-wrapper, .woocommerce-shipping-fields__field-wrapper, .woocommerce-address-fields__field-wrapper, .woocommerce-additional-fields__field-wrapper .woocommerce-account-fields'); - - fieldsets.each( function( index, fieldset ) { - var rows = $( fieldset ).find( '.form-row' ); - var wrapper = rows.first().parent(); - - // Before sorting, ensure all fields have a priority for bW compatibility. - var last_priority = 0; - - rows.each( function() { - if ( ! $( this ).data( 'priority' ) ) { - $( this ).data( 'priority', last_priority + 1 ); - } - last_priority = $( this ).data( 'priority' ); - } ); - - // Sort the fields. - rows.sort( function( a, b ) { - var asort = $( a ).data( 'priority' ), - bsort = $( b ).data( 'priority' ); - - if ( asort > bsort ) { - return 1; - } - if ( asort < bsort ) { - return -1; - } - return 0; - }); - - rows.detach().appendTo( wrapper ); - } ); + if ( asort > bsort ) { + return 1; + } + if ( asort < bsort ) { + return -1; + } + return 0; }); + + rows.detach().appendTo( wrapper ); + } ); }); +}); diff --git a/i18n/languages/woocommerce.pot b/i18n/languages/woocommerce.pot index 6e52b113f78..5b2b01a488f 100644 --- a/i18n/languages/woocommerce.pot +++ b/i18n/languages/woocommerce.pot @@ -26184,11 +26184,6 @@ msgstr "" msgid "You’ve received the following order from %s:" msgstr "" -#: templates/emails/admin-new-order.php:50 -#: templates/emails/plain/admin-new-order.php:50 -msgid "Over to you." -msgstr "" - #: templates/emails/customer-completed-order.php:28 #: templates/emails/customer-invoice.php:30 #: templates/emails/customer-new-account.php:27 diff --git a/includes/abstracts/abstract-wc-rest-terms-controller.php b/includes/abstracts/abstract-wc-rest-terms-controller.php index 8f8cbccb213..7c6bbb65d14 100644 --- a/includes/abstracts/abstract-wc-rest-terms-controller.php +++ b/includes/abstracts/abstract-wc-rest-terms-controller.php @@ -533,6 +533,14 @@ abstract class WC_REST_Terms_Controller extends WC_REST_Controller { } $term = get_term( (int) $request['id'], $taxonomy ); + // Get default category id. + $default_category_id = absint( get_option( 'default_product_cat', 0 ) ); + + // Prevent deleting the default product category. + if ( $default_category_id === (int) $request['id'] ) { + return new WP_Error( 'woocommerce_rest_cannot_delete', __( 'Default product category cannot be deleted.', 'woocommerce' ), array( 'status' => 500 ) ); + } + $request->set_param( 'context', 'edit' ); $response = $this->prepare_item_for_response( $term, $request ); @@ -686,7 +694,7 @@ abstract class WC_REST_Terms_Controller extends WC_REST_Controller { $params['context']['default'] = 'view'; $params['exclude'] = array( - 'description' => __( 'Ensure result set excludes specific ids.', 'woocommerce' ), + 'description' => __( 'Ensure result set excludes specific IDs.', 'woocommerce' ), 'type' => 'array', 'items' => array( 'type' => 'integer', diff --git a/includes/admin/class-wc-admin-dashboard.php b/includes/admin/class-wc-admin-dashboard.php index 692fdea58eb..09a19572491 100644 --- a/includes/admin/class-wc-admin-dashboard.php +++ b/includes/admin/class-wc-admin-dashboard.php @@ -275,7 +275,7 @@ if ( ! class_exists( 'WC_Admin_Dashboard', false ) ) : "FROM {$wpdb->comments} comments LEFT JOIN {$wpdb->posts} posts ON (comments.comment_post_ID = posts.ID) WHERE comments.comment_approved = '1' - AND comments.comment_type = '' + AND comments.comment_type = 'review' AND posts.post_password = '' AND posts.post_type = 'product' AND comments.comment_parent = 0 diff --git a/includes/admin/class-wc-admin-webhooks.php b/includes/admin/class-wc-admin-webhooks.php index abe82d2df79..c4216044c3e 100644 --- a/includes/admin/class-wc-admin-webhooks.php +++ b/includes/admin/class-wc-admin-webhooks.php @@ -119,7 +119,8 @@ class WC_Admin_Webhooks { } // API version. - $webhook->set_api_version( ! empty( $_POST['webhook_api_version'] ) ? sanitize_text_field( wp_unslash( $_POST['webhook_api_version'] ) ) : 'wp_api_v2' ); // WPCS: input var okay, CSRF ok. + $rest_api_versions = wc_get_webhook_rest_api_versions(); + $webhook->set_api_version( ! empty( $_POST['webhook_api_version'] ) ? sanitize_text_field( wp_unslash( $_POST['webhook_api_version'] ) ) : end( $rest_api_versions ) ); // WPCS: input var okay, CSRF ok. $webhook->save(); diff --git a/includes/admin/helper/views/html-oauth-start.php b/includes/admin/helper/views/html-oauth-start.php index 7326ff08fc8..36e87259e42 100644 --- a/includes/admin/helper/views/html-oauth-start.php +++ b/includes/admin/helper/views/html-oauth-start.php @@ -19,7 +19,7 @@ defined( 'ABSPATH' ) || exit(); WooCommerce -

Sorry to see you go. Feel free to reconnect again using the button below.', 'woocommerce' ); ?>

+

' . esc_html_e( 'Feel free to reconnect again using the button below.', 'woocommerce' ); ?>

diff --git a/includes/admin/list-tables/class-wc-admin-list-table-orders.php b/includes/admin/list-tables/class-wc-admin-list-table-orders.php index f9babc8825b..1b562292c2a 100644 --- a/includes/admin/list-tables/class-wc-admin-list-table-orders.php +++ b/includes/admin/list-tables/class-wc-admin-list-table-orders.php @@ -772,22 +772,15 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table { // Filter the orders by the posted customer. if ( ! empty( $_GET['_customer_user'] ) ) { // WPCS: input var ok. - $customer_id = (int) $_GET['_customer_user']; // WPCS: input var ok, sanitization ok. - - // On WC 3.5.0 the ID of the user that placed the order was moved from the post meta _customer_user to the post_author field in the wp_posts table. - if ( version_compare( get_option( 'woocommerce_db_version' ), '3.5.0', '>=' ) ) { - $query_vars['author'] = $customer_id; - } else { - // @codingStandardsIgnoreStart - $query_vars['meta_query'] = array( - array( - 'key' => '_customer_user', - 'value' => $customer_id, - 'compare' => '=', - ), - ); - // @codingStandardsIgnoreEnd - } + // @codingStandardsIgnoreStart + $query_vars['meta_query'] = array( + array( + 'key' => '_customer_user', + 'value' => (int) $_GET['_customer_user'], // WPCS: input var ok, sanitization ok. + 'compare' => '=', + ), + ); + // @codingStandardsIgnoreEnd } // Sorting. diff --git a/includes/admin/reports/class-wc-report-customers.php b/includes/admin/reports/class-wc-report-customers.php index 326ad5334f5..503f470992f 100644 --- a/includes/admin/reports/class-wc-report-customers.php +++ b/includes/admin/reports/class-wc-report-customers.php @@ -69,56 +69,46 @@ class WC_Report_Customers extends WC_Admin_Report { * Output customers vs guests chart. */ public function customers_vs_guests() { - $customer_args = array( - 'data' => array( - 'ID' => array( - 'type' => 'post_data', - 'function' => 'COUNT', - 'name' => 'total_orders', + + $customer_order_totals = $this->get_order_report_data( + array( + 'data' => array( + 'ID' => array( + 'type' => 'post_data', + 'function' => 'COUNT', + 'name' => 'total_orders', + ), ), - ), - 'filter_range' => true, + 'where_meta' => array( + array( + 'meta_key' => '_customer_user', + 'meta_value' => '0', + 'operator' => '>', + ), + ), + 'filter_range' => true, + ) ); - $guest_args = $customer_args; - // On WC 3.5.0 the ID of the user that placed the order was moved from the post meta _customer_user to the post_author field in the wp_posts table. - if ( version_compare( get_option( 'woocommerce_db_version' ), '3.5.0', '>=' ) ) { - $customer_args['where'] = array( - array( - 'key' => 'post_author', - 'value' => '0', - 'operator' => '>', + $guest_order_totals = $this->get_order_report_data( + array( + 'data' => array( + 'ID' => array( + 'type' => 'post_data', + 'function' => 'COUNT', + 'name' => 'total_orders', + ), ), - ); - - $guest_args['where'] = array( - array( - 'key' => 'post_author', - 'value' => '0', - 'operator' => '=', + 'where_meta' => array( + array( + 'meta_key' => '_customer_user', + 'meta_value' => '0', + 'operator' => '=', + ), ), - ); - } else { - $customer_args['where_meta'] = array( - array( - 'meta_key' => '_customer_user', - 'meta_value' => '0', - 'operator' => '>', - ), - ); - - $guest_args['where_meta'] = array( - array( - 'meta_key' => '_customer_user', - 'meta_value' => '0', - 'operator' => '=', - ), - ); - } - - $customer_order_totals = $this->get_order_report_data( $customer_args ); - $guest_order_totals = $this->get_order_report_data( $guest_args ); - + 'filter_range' => true, + ) + ); ?>
@@ -256,63 +246,61 @@ class WC_Report_Customers extends WC_Admin_Report { public function get_main_chart() { global $wp_locale; - $customer_args = array( - 'data' => array( - 'ID' => array( - 'type' => 'post_data', - 'function' => 'COUNT', - 'name' => 'total_orders', + $customer_orders = $this->get_order_report_data( + array( + 'data' => array( + 'ID' => array( + 'type' => 'post_data', + 'function' => 'COUNT', + 'name' => 'total_orders', + ), + 'post_date' => array( + 'type' => 'post_data', + 'function' => '', + 'name' => 'post_date', + ), ), - 'post_date' => array( - 'type' => 'post_data', - 'function' => '', - 'name' => 'post_date', + 'where_meta' => array( + array( + 'meta_key' => '_customer_user', + 'meta_value' => '0', + 'operator' => '>', + ), ), - ), - 'group_by' => $this->group_by_query, - 'order_by' => 'post_date ASC', - 'query_type' => 'get_results', - 'filter_range' => true, + 'group_by' => $this->group_by_query, + 'order_by' => 'post_date ASC', + 'query_type' => 'get_results', + 'filter_range' => true, + ) ); - $guest_args = $customer_args; - // On WC 3.5.0 the ID of the user that placed the order was moved from the post meta _customer_user to the post_author field in the wp_posts table. - if ( version_compare( get_option( 'woocommerce_db_version' ), '3.5.0', '>=' ) ) { - $customer_args['where'] = array( - array( - 'key' => 'post_author', - 'value' => '0', - 'operator' => '>', + $guest_orders = $this->get_order_report_data( + array( + 'data' => array( + 'ID' => array( + 'type' => 'post_data', + 'function' => 'COUNT', + 'name' => 'total_orders', + ), + 'post_date' => array( + 'type' => 'post_data', + 'function' => '', + 'name' => 'post_date', + ), ), - ); - - $guest_args['where'] = array( - array( - 'key' => 'post_author', - 'value' => '0', - 'operator' => '=', + 'where_meta' => array( + array( + 'meta_key' => '_customer_user', + 'meta_value' => '0', + 'operator' => '=', + ), ), - ); - } else { - $customer_args['where_meta'] = array( - array( - 'meta_key' => '_customer_user', - 'meta_value' => '0', - 'operator' => '>', - ), - ); - - $guest_args['where_meta'] = array( - array( - 'meta_key' => '_customer_user', - 'meta_value' => '0', - 'operator' => '=', - ), - ); - } - - $customer_orders = $this->get_order_report_data( $customer_args ); - $guest_orders = $this->get_order_report_data( $guest_args ); + 'group_by' => $this->group_by_query, + 'order_by' => 'post_date ASC', + 'query_type' => 'get_results', + 'filter_range' => true, + ) + ); $signups = $this->prepare_chart_data( $this->customers, 'user_registered', '', $this->chart_interval, $this->start_date, $this->chart_groupby ); $customer_orders = $this->prepare_chart_data( $customer_orders, 'post_date', 'total_orders', $this->chart_interval, $this->start_date, $this->chart_groupby ); diff --git a/includes/admin/settings/views/html-webhooks-edit.php b/includes/admin/settings/views/html-webhooks-edit.php index 7eda686449e..831bfec2a33 100644 --- a/includes/admin/settings/views/html-webhooks-edit.php +++ b/includes/admin/settings/views/html-webhooks-edit.php @@ -136,8 +136,14 @@ if ( ! defined( 'ABSPATH' ) ) { diff --git a/includes/api/class-wc-rest-product-reviews-controller.php b/includes/api/class-wc-rest-product-reviews-controller.php index 98e66734fb9..602b1b5f8dd 100644 --- a/includes/api/class-wc-rest-product-reviews-controller.php +++ b/includes/api/class-wc-rest-product-reviews-controller.php @@ -391,7 +391,7 @@ class WC_REST_Product_Reviews_Controller extends WC_REST_Controller { * Do not allow a comment to be created with missing or empty comment_content. See wp_handle_comment_submission(). */ if ( empty( $prepared_review['comment_content'] ) ) { - return new WP_Error( 'wc_rest_review_content_invalid', __( 'Invalid product review content.', 'woocommerce' ), array( 'status' => 400 ) ); + return new WP_Error( 'woocommerce_rest_review_content_invalid', __( 'Invalid review content.', 'woocommerce' ), array( 'status' => 400 ) ); } // Setting remaining values before wp_insert_comment so we can use wp_allow_comment(). @@ -926,7 +926,7 @@ class WC_REST_Product_Reviews_Controller extends WC_REST_Controller { $params['context']['default'] = 'view'; $params['after'] = array( - 'description' => __( 'Limit response to reviews published after a given ISO8601 compliant date.', 'woocommerce' ), + 'description' => __( 'Limit response to resources published after a given ISO8601 compliant date.', 'woocommerce' ), 'type' => 'string', 'format' => 'date-time', ); diff --git a/includes/api/class-wc-rest-products-controller.php b/includes/api/class-wc-rest-products-controller.php index d064fd74e92..bfbd88115bb 100644 --- a/includes/api/class-wc-rest-products-controller.php +++ b/includes/api/class-wc-rest-products-controller.php @@ -665,7 +665,7 @@ class WC_REST_Products_Controller extends WC_REST_Products_V2_Controller { $date = rest_parse_date( $request['date_created_gmt'], true ); if ( $date ) { - $product->set_date_created_gmt( $date ); + $product->set_date_created( $date ); } } diff --git a/includes/api/class-wc-rest-webhooks-controller.php b/includes/api/class-wc-rest-webhooks-controller.php index f876adb3f21..99e1c70a729 100644 --- a/includes/api/class-wc-rest-webhooks-controller.php +++ b/includes/api/class-wc-rest-webhooks-controller.php @@ -24,4 +24,14 @@ class WC_REST_Webhooks_Controller extends WC_REST_Webhooks_V2_Controller { * @var string */ protected $namespace = 'wc/v3'; + + /** + * Get the default REST API version. + * + * @since 3.0.0 + * @return string + */ + protected function get_default_api_version() { + return 'wp_api_v3'; + } } diff --git a/includes/api/v1/class-wc-rest-orders-controller.php b/includes/api/v1/class-wc-rest-orders-controller.php index f617192c0bb..804e3fb571e 100644 --- a/includes/api/v1/class-wc-rest-orders-controller.php +++ b/includes/api/v1/class-wc-rest-orders-controller.php @@ -404,20 +404,15 @@ class WC_REST_Orders_V1_Controller extends WC_REST_Posts_Controller { } if ( isset( $request['customer'] ) ) { - // On WC 3.5.0 the ID of the user that placed the order was moved from the post meta _customer_user to the post_author field in the wp_posts table. - if ( version_compare( get_option( 'woocommerce_db_version' ), '3.5.0', '>=' ) ) { - $args['author'] = $request['customer']; - } else { - if ( ! empty( $args['meta_query'] ) ) { - $args['meta_query'] = array(); // WPCS: slow query ok. - } - - $args['meta_query'][] = array( - 'key' => '_customer_user', - 'value' => $request['customer'], - 'type' => 'NUMERIC', - ); + if ( ! empty( $args['meta_query'] ) ) { + $args['meta_query'] = array(); } + + $args['meta_query'][] = array( + 'key' => '_customer_user', + 'value' => $request['customer'], + 'type' => 'NUMERIC', + ); } // Search by product. diff --git a/includes/api/v2/class-wc-rest-orders-v2-controller.php b/includes/api/v2/class-wc-rest-orders-v2-controller.php index 85ebdac6af3..85675a4fbde 100644 --- a/includes/api/v2/class-wc-rest-orders-v2-controller.php +++ b/includes/api/v2/class-wc-rest-orders-v2-controller.php @@ -367,20 +367,15 @@ class WC_REST_Orders_V2_Controller extends WC_REST_Legacy_Orders_Controller { } if ( isset( $request['customer'] ) ) { - // On WC 3.5.0 the ID of the user that placed the order was moved from the post meta _customer_user to the post_author field in the wp_posts table. - if ( version_compare( get_option( 'woocommerce_db_version' ), '3.5.0', '>=' ) ) { - $args['author'] = $request['customer']; - } else { - if ( ! empty( $args['meta_query'] ) ) { - $args['meta_query'] = array(); // WPCS: slow query ok. - } - - $args['meta_query'][] = array( - 'key' => '_customer_user', - 'value' => $request['customer'], - 'type' => 'NUMERIC', - ); + if ( ! empty( $args['meta_query'] ) ) { + $args['meta_query'] = array(); // WPCS: slow query ok. } + + $args['meta_query'][] = array( + 'key' => '_customer_user', + 'value' => $request['customer'], + 'type' => 'NUMERIC', + ); } // Search by product. diff --git a/includes/class-wc-cart-session.php b/includes/class-wc-cart-session.php index 83d4ce549d4..404abadebc8 100644 --- a/includes/class-wc-cart-session.php +++ b/includes/class-wc-cart-session.php @@ -61,6 +61,7 @@ final class WC_Cart_Session { * @since 3.2.0 */ public function get_cart_from_session() { + do_action( 'woocommerce_load_cart_from_session' ); $this->cart->set_totals( WC()->session->get( 'cart_totals', null ) ); $this->cart->set_applied_coupons( WC()->session->get( 'applied_coupons', array() ) ); $this->cart->set_coupon_discount_totals( WC()->session->get( 'coupon_discount_totals', array() ) ); diff --git a/includes/class-wc-cart.php b/includes/class-wc-cart.php index 1b3c3fda2be..124d7ab7c8b 100644 --- a/includes/class-wc-cart.php +++ b/includes/class-wc-cart.php @@ -143,7 +143,7 @@ class WC_Cart extends WC_Legacy_Cart { * @return array of cart items */ public function get_cart_contents() { - return (array) $this->cart_contents; + return apply_filters( 'woocommerce_get_cart_contents', (array) $this->cart_contents ); } /** @@ -603,7 +603,7 @@ class WC_Cart extends WC_Legacy_Cart { if ( ! did_action( 'wp_loaded' ) ) { wc_doing_it_wrong( __FUNCTION__, __( 'Get cart should not be called before the wp_loaded action.', 'woocommerce' ), '2.3' ); } - if ( ! did_action( 'woocommerce_cart_loaded_from_session' ) ) { + if ( ! did_action( 'woocommerce_load_cart_from_session' ) ) { $this->session->get_cart_from_session(); } return array_filter( $this->get_cart_contents() ); @@ -1374,11 +1374,6 @@ class WC_Cart extends WC_Legacy_Cart { } } - // If we're on the cart page, the user has not calculated shipping, hide the area. - if ( is_cart() && ! $this->get_customer()->has_calculated_shipping() ) { - return false; - } - return apply_filters( 'woocommerce_cart_ready_to_calc_shipping', true ); } diff --git a/includes/class-wc-checkout.php b/includes/class-wc-checkout.php index 8b42234611a..1722a1f611b 100644 --- a/includes/class-wc-checkout.php +++ b/includes/class-wc-checkout.php @@ -238,9 +238,13 @@ class WC_Checkout { 'placeholder' => esc_attr__( 'Password', 'woocommerce' ), ); } - $this->fields = apply_filters( 'woocommerce_checkout_fields', $this->fields ); + foreach ( $this->fields as $field_type => $fields ) { + // Sort each of the checkout field sections based on priority. + uasort( $this->fields[ $field_type ], 'wc_checkout_fields_uasort_comparison' ); + } + return $fieldset ? $this->fields[ $fieldset ] : $this->fields; } diff --git a/includes/class-wc-countries.php b/includes/class-wc-countries.php index 6b7581cbd65..535477b8d38 100644 --- a/includes/class-wc-countries.php +++ b/includes/class-wc-countries.php @@ -662,8 +662,8 @@ class WC_Countries { 'priority' => 50, ), 'address_2' => array( - 'label' => __( 'Apartment, suite, or unit.', 'woocommerce' ), - 'label_class' => 'screen-reader-text', + 'label' => __( 'Apartment, suite, unit etc.', 'woocommerce' ), + 'label_class' => array( 'screen-reader-text' ), 'placeholder' => esc_attr( $address_2_placeholder ), 'class' => array( 'form-row-wide', 'address-field' ), 'autocomplete' => 'address-line2', @@ -1012,12 +1012,12 @@ class WC_Countries { ), 'NG' => array( 'postcode' => array( - 'label' => __( 'Postcode', 'woocommerce' ), + 'label' => __( 'Postcode', 'woocommerce' ), 'required' => false, 'hidden' => true, ), 'state' => array( - 'label' => __( 'State', 'woocommerce' ), + 'label' => __( 'State', 'woocommerce' ), ), ), 'NZ' => array( diff --git a/includes/class-wc-install.php b/includes/class-wc-install.php index 6f372b3c583..2421e1e5523 100644 --- a/includes/class-wc-install.php +++ b/includes/class-wc-install.php @@ -114,7 +114,6 @@ class WC_Install { 'wc_update_344_db_version', ), '3.5.0' => array( - 'wc_update_350_order_customer_id', 'wc_update_350_reviews_comment_type', 'wc_update_350_db_version', ), diff --git a/includes/class-wc-post-types.php b/includes/class-wc-post-types.php index 09d810292bd..edd10d69947 100644 --- a/includes/class-wc-post-types.php +++ b/includes/class-wc-post-types.php @@ -27,6 +27,7 @@ class WC_Post_Types { add_action( 'woocommerce_after_register_post_type', array( __CLASS__, 'maybe_flush_rewrite_rules' ) ); add_action( 'woocommerce_flush_rewrite_rules', array( __CLASS__, 'flush_rewrite_rules' ) ); add_filter( 'gutenberg_can_edit_post_type', array( __CLASS__, 'gutenberg_can_edit_post_type' ), 10, 2 ); + add_filter( 'use_block_editor_for_post_type', array( __CLASS__, 'gutenberg_can_edit_post_type' ), 10, 2 ); } /** diff --git a/includes/class-wc-webhook.php b/includes/class-wc-webhook.php index 5306f6e1b7e..9c02f274994 100644 --- a/includes/class-wc-webhook.php +++ b/includes/class-wc-webhook.php @@ -280,7 +280,8 @@ class WC_Webhook extends WC_Legacy_Webhook { * @return array */ private function get_wp_api_payload( $resource, $resource_id, $event ) { - $version_suffix = 'wp_api_v1' === $this->get_api_version() ? '_V1' : ''; + $rest_api_versions = wc_get_webhook_rest_api_versions(); + $version_suffix = end( $rest_api_versions ) === $this->get_api_version() ? strtoupper( str_replace( 'wp_api', '', $this->get_api_version() ) ) : ''; switch ( $resource ) { case 'coupon': @@ -340,7 +341,7 @@ class WC_Webhook extends WC_Legacy_Webhook { 'id' => $resource_id, ); } else { - if ( in_array( $this->get_api_version(), array( 'wp_api_v1', 'wp_api_v2' ), true ) ) { + if ( in_array( $this->get_api_version(), wc_get_webhook_rest_api_versions(), true ) ) { $payload = $this->get_wp_api_payload( $resource, $resource_id, $event ); } else { $payload = $this->get_legacy_api_payload( $resource, $resource_id, $event ); diff --git a/includes/data-stores/abstract-wc-order-data-store-cpt.php b/includes/data-stores/abstract-wc-order-data-store-cpt.php index 0d6208887da..73ff2844cb0 100644 --- a/includes/data-stores/abstract-wc-order-data-store-cpt.php +++ b/includes/data-stores/abstract-wc-order-data-store-cpt.php @@ -67,7 +67,7 @@ abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP impleme 'post_type' => $order->get_type( 'edit' ), 'post_status' => 'wc-' . ( $order->get_status( 'edit' ) ? $order->get_status( 'edit' ) : apply_filters( 'woocommerce_default_order_status', 'pending' ) ), 'ping_status' => 'closed', - 'post_author' => is_callable( array( $order, 'get_customer_id' ) ) ? $order->get_customer_id() : 0, + 'post_author' => 1, 'post_title' => $this->get_post_title(), 'post_password' => uniqid( 'order_' ), 'post_parent' => $order->get_parent_id( 'edit' ), @@ -139,7 +139,7 @@ abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP impleme $changes = $order->get_changes(); // Only update the post when the post data changes. - if ( array_intersect( array( 'date_created', 'date_modified', 'status', 'parent_id', 'post_excerpt', 'customer_id' ), array_keys( $changes ) ) ) { + if ( array_intersect( array( 'date_created', 'date_modified', 'status', 'parent_id', 'post_excerpt' ), array_keys( $changes ) ) ) { $post_data = array( 'post_date' => gmdate( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getOffsetTimestamp() ), 'post_date_gmt' => gmdate( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getTimestamp() ), @@ -148,7 +148,6 @@ abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP impleme 'post_excerpt' => $this->get_post_excerpt( $order ), 'post_modified' => isset( $changes['date_modified'] ) ? gmdate( 'Y-m-d H:i:s', $order->get_date_modified( 'edit' )->getOffsetTimestamp() ) : current_time( 'mysql' ), 'post_modified_gmt' => isset( $changes['date_modified'] ) ? gmdate( 'Y-m-d H:i:s', $order->get_date_modified( 'edit' )->getTimestamp() ) : current_time( 'mysql', 1 ), - 'post_author' => is_callable( array( $order, 'get_customer_id' ) ) ? $order->get_customer_id() : 0, ); /** @@ -166,27 +165,12 @@ abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP impleme wp_update_post( array_merge( array( 'ID' => $order->get_id() ), $post_data ) ); } $order->read_meta_data( true ); // Refresh internal meta data, in case things were hooked into `save_post` or another WP hook. - - // If customer changed, update any downloadable permissions. - if ( in_array( 'customer_id', $changes ) ) { - $this->update_downloadable_permissions( $order ); - } } $this->update_post_meta( $order ); $order->apply_changes(); $this->clear_caches( $order ); } - /** - * Update downloadable permissions for a given order. - * - * @param WC_Order $order Order object. - */ - protected function update_downloadable_permissions( $order ) { - $data_store = WC_Data_Store::load( 'customer-download' ); - $data_store->update_user_by_order_id( $order->get_id(), $order->get_customer_id(), $order->get_billing_email() ); - } - /** * Method to delete an order from the database. * diff --git a/includes/data-stores/class-wc-customer-data-store.php b/includes/data-stores/class-wc-customer-data-store.php index 8ad38340b3f..d907e61893c 100644 --- a/includes/data-stores/class-wc-customer-data-store.php +++ b/includes/data-stores/class-wc-customer-data-store.php @@ -325,27 +325,18 @@ class WC_Customer_Data_Store extends WC_Data_Store_WP implements WC_Customer_Dat public function get_last_order( &$customer ) { global $wpdb; - // On WC 3.5.0 the ID of the user that placed the order was moved from the post meta _customer_user to the post_author field in the wp_posts table. - if ( version_compare( get_option( 'woocommerce_db_version' ), '3.5.0', '>=' ) ) { - $query = "SELECT ID - FROM $wpdb->posts - WHERE post_author = '" . esc_sql( $customer->get_id() ) . "' - AND post_type = 'shop_order' - AND post_status IN ( '" . implode( "','", array_map( 'esc_sql', array_keys( wc_get_order_statuses() ) ) ) . "' ) - ORDER BY ID DESC"; - } else { - $query = "SELECT posts.ID + $last_order = $wpdb->get_var( + // phpcs:disable WordPress.WP.PreparedSQL.NotPrepared + "SELECT posts.ID FROM $wpdb->posts AS posts LEFT JOIN {$wpdb->postmeta} AS meta on posts.ID = meta.post_id WHERE meta.meta_key = '_customer_user' AND meta.meta_value = '" . esc_sql( $customer->get_id() ) . "' AND posts.post_type = 'shop_order' AND posts.post_status IN ( '" . implode( "','", array_map( 'esc_sql', array_keys( wc_get_order_statuses() ) ) ) . "' ) - ORDER BY posts.ID DESC"; - } - - // phpcs:ignore WordPress.WP.PreparedSQL.NotPrepared - $last_order = $wpdb->get_var( $query ); + ORDER BY posts.ID DESC" + // phpcs:enable + ); if ( ! $last_order ) { return false; @@ -367,25 +358,17 @@ class WC_Customer_Data_Store extends WC_Data_Store_WP implements WC_Customer_Dat if ( '' === $count ) { global $wpdb; - // On WC 3.5.0 the ID of the user that placed the order was moved from the post meta _customer_user to the post_author field in the wp_posts table. - if ( version_compare( get_option( 'woocommerce_db_version' ), '3.5.0', '>=' ) ) { - $query = "SELECT COUNT(*) - FROM $wpdb->posts - WHERE post_type = 'shop_order' - AND post_status IN ( '" . implode( "','", array_map( 'esc_sql', array_keys( wc_get_order_statuses() ) ) ) . "' ) - AND post_author = " . esc_sql( $customer->get_id() ); - } else { - $query = "SELECT COUNT(*) + $count = $wpdb->get_var( + // phpcs:disable WordPress.WP.PreparedSQL.NotPrepared + "SELECT COUNT(*) FROM $wpdb->posts as posts LEFT JOIN {$wpdb->postmeta} AS meta ON posts.ID = meta.post_id WHERE meta.meta_key = '_customer_user' AND posts.post_type = 'shop_order' AND posts.post_status IN ( '" . implode( "','", array_map( 'esc_sql', array_keys( wc_get_order_statuses() ) ) ) . "' ) - AND meta_value = '" . esc_sql( $customer->get_id() ) . "'"; - } - - // phpcs:ignore WordPress.WP.PreparedSQL.NotPrepared - $count = $wpdb->get_var( $query ); + AND meta_value = '" . esc_sql( $customer->get_id() ) . "'" + // phpcs:enable + ); update_user_meta( $customer->get_id(), '_order_count', $count ); } @@ -410,18 +393,11 @@ class WC_Customer_Data_Store extends WC_Data_Store_WP implements WC_Customer_Dat global $wpdb; $statuses = array_map( 'esc_sql', wc_get_is_paid_statuses() ); - - // On WC 3.5.0 the ID of the user that placed the order was moved from the post meta _customer_user to the post_author field in the wp_posts table. - if ( version_compare( get_option( 'woocommerce_db_version' ), '3.5.0', '>=' ) ) { - $query = "SELECT SUM(meta.meta_value) - FROM $wpdb->posts as posts - LEFT JOIN {$wpdb->postmeta} AS meta ON posts.ID = meta.post_id - WHERE posts.post_author = '" . esc_sql( $customer->get_id() ) . "' - AND posts.post_type = 'shop_order' - AND posts.post_status IN ( 'wc-" . implode( "','wc-", $statuses ) . "' ) - AND meta.meta_key = '_order_total'"; - } else { - $query = "SELECT SUM(meta2.meta_value) + $spent = $wpdb->get_var( + // phpcs:disable WordPress.WP.PreparedSQL.NotPrepared + apply_filters( + 'woocommerce_customer_get_total_spent_query', + "SELECT SUM(meta2.meta_value) FROM $wpdb->posts as posts LEFT JOIN {$wpdb->postmeta} AS meta ON posts.ID = meta.post_id LEFT JOIN {$wpdb->postmeta} AS meta2 ON posts.ID = meta2.post_id @@ -429,11 +405,11 @@ class WC_Customer_Data_Store extends WC_Data_Store_WP implements WC_Customer_Dat AND meta.meta_value = '" . esc_sql( $customer->get_id() ) . "' AND posts.post_type = 'shop_order' AND posts.post_status IN ( 'wc-" . implode( "','wc-", $statuses ) . "' ) - AND meta2.meta_key = '_order_total'"; - } - - // phpcs:ignore WordPress.WP.PreparedSQL.NotPrepared - $spent = $wpdb->get_var( apply_filters( 'woocommerce_customer_get_total_spent_query', $query, $customer ) ); + AND meta2.meta_key = '_order_total'", + $customer + ) + // phpcs:enable + ); if ( ! $spent ) { $spent = 0; diff --git a/includes/data-stores/class-wc-order-data-store-cpt.php b/includes/data-stores/class-wc-order-data-store-cpt.php index 316aa4b8373..c117b6bef63 100644 --- a/includes/data-stores/class-wc-order-data-store-cpt.php +++ b/includes/data-stores/class-wc-order-data-store-cpt.php @@ -107,17 +107,10 @@ class WC_Order_Data_Store_CPT extends Abstract_WC_Order_Data_Store_CPT implement $date_paid = get_post_meta( $id, '_paid_date', true ); } - // On WC 3.5.0 the ID of the user that placed the order was moved from the post meta _customer_user to the post_author field in the wp_posts table. - if ( version_compare( get_option( 'woocommerce_db_version' ), '3.5.0', '>=' ) ) { - $customer_id = $post_object->post_author; - } else { - $customer_id = get_post_meta( $id, '_customer_user', true ); - } - $order->set_props( array( 'order_key' => get_post_meta( $id, '_order_key', true ), - 'customer_id' => $customer_id, + 'customer_id' => get_post_meta( $id, '_customer_user', true ), 'billing_first_name' => get_post_meta( $id, '_billing_first_name', true ), 'billing_last_name' => get_post_meta( $id, '_billing_last_name', true ), 'billing_company' => get_post_meta( $id, '_billing_company', true ), @@ -265,9 +258,10 @@ class WC_Order_Data_Store_CPT extends Abstract_WC_Order_Data_Store_CPT implement update_post_meta( $id, '_shipping_address_index', implode( ' ', $order->get_address( 'shipping' ) ) ); } - // If customer email changed, update any downloadable permissions. - if ( in_array( 'billing_email', $updated_props ) ) { - $this->update_downloadable_permissions( $order ); + // If customer changed, update any downloadable permissions. + if ( in_array( 'customer_id', $updated_props ) || in_array( 'billing_email', $updated_props ) ) { + $data_store = WC_Data_Store::load( 'customer-download' ); + $data_store->update_user_by_order_id( $id, $order->get_customer_id(), $order->get_billing_email() ); } // Mark user account as active. @@ -651,11 +645,6 @@ class WC_Order_Data_Store_CPT extends Abstract_WC_Order_Data_Store_CPT implement 'page' => 'paged', ); - // On WC 3.5.0 the ID of the user that placed the order was moved from the post meta _customer_user to the post_author field in the wp_posts table. - if ( version_compare( get_option( 'woocommerce_db_version' ), '3.5.0', '>=' ) ) { - $key_mapping['customer_id'] = 'author'; - } - foreach ( $key_mapping as $query_key => $db_key ) { if ( isset( $query_vars[ $query_key ] ) ) { $query_vars[ $db_key ] = $query_vars[ $query_key ]; diff --git a/includes/gateways/paypal/includes/class-wc-gateway-paypal-pdt-handler.php b/includes/gateways/paypal/includes/class-wc-gateway-paypal-pdt-handler.php index 23db0aa6a94..92b05236fd7 100644 --- a/includes/gateways/paypal/includes/class-wc-gateway-paypal-pdt-handler.php +++ b/includes/gateways/paypal/includes/class-wc-gateway-paypal-pdt-handler.php @@ -106,7 +106,7 @@ class WC_Gateway_Paypal_PDT_Handler extends WC_Gateway_Paypal_Response { update_post_meta( $order->get_id(), '_transaction_id', $transaction ); if ( 'completed' === $status ) { - if ( $order->get_total() !== $amount ) { + if ( number_format( $order->get_total(), 2, '.', '' ) !== number_format( $amount, 2, '.', '' ) ) { WC_Gateway_Paypal::log( 'Payment error: Amounts do not match (amt ' . $amount . ')', 'error' ); /* translators: 1: Payment amount */ $this->payment_on_hold( $order, sprintf( __( 'Validation error: PayPal amounts do not match (amt %s).', 'woocommerce' ), $amount ) ); diff --git a/includes/gateways/paypal/includes/settings-paypal.php b/includes/gateways/paypal/includes/settings-paypal.php index 50269794ce0..00bad8a706e 100644 --- a/includes/gateways/paypal/includes/settings-paypal.php +++ b/includes/gateways/paypal/includes/settings-paypal.php @@ -153,7 +153,7 @@ return array( ), 'api_signature' => array( 'title' => __( 'Live API signature', 'woocommerce' ), - 'type' => 'text', + 'type' => 'password', 'description' => __( 'Get your API credentials from PayPal.', 'woocommerce' ), 'default' => '', 'desc_tip' => true, @@ -177,7 +177,7 @@ return array( ), 'sandbox_api_signature' => array( 'title' => __( 'Sandbox API signature', 'woocommerce' ), - 'type' => 'text', + 'type' => 'password', 'description' => __( 'Get your API credentials from PayPal.', 'woocommerce' ), 'default' => '', 'desc_tip' => true, diff --git a/includes/wc-core-functions.php b/includes/wc-core-functions.php index f9ab2265457..db55521faf7 100644 --- a/includes/wc-core-functions.php +++ b/includes/wc-core-functions.php @@ -1499,10 +1499,7 @@ function wc_nocache_headers() { * @return int */ function wc_product_attribute_uasort_comparison( $a, $b ) { - if ( $a['position'] === $b['position'] ) { - return 0; - } - return ( $a['position'] < $b['position'] ) ? -1 : 1; + return wc_uasort_comparison( $a['position'], $b['position'] ); } /** @@ -1514,10 +1511,34 @@ function wc_product_attribute_uasort_comparison( $a, $b ) { * @return int */ function wc_shipping_zone_method_order_uasort_comparison( $a, $b ) { - if ( $a->method_order === $b->method_order ) { + return wc_uasort_comparison( $a->method_order, $b->method_order ); +} + +/** + * User to sort checkout fields based on priority with uasort. + * + * @since 3.5.1 + * @param array $a First field to compare. + * @param array $b Second field to compare. + * @return int + */ +function wc_checkout_fields_uasort_comparison( $a, $b ) { + return wc_uasort_comparison( $a['priority'], $b['priority'] ); +} + +/** + * User to sort two values with ausort. + * + * @since 3.5.1 + * @param int $a First value to compare. + * @param int $b Second value to compare. + * @return int + */ +function wc_uasort_comparison( $a, $b ) { + if ( $a === $b ) { return 0; } - return ( $a->method_order < $b->method_order ) ? -1 : 1; + return ( $a < $b ) ? -1 : 1; } /** diff --git a/includes/wc-formatting-functions.php b/includes/wc-formatting-functions.php index 0c8d439b70a..80ed8b30608 100644 --- a/includes/wc-formatting-functions.php +++ b/includes/wc-formatting-functions.php @@ -378,7 +378,7 @@ function wc_clean( $var ) { } /** - * wp_check_invalid_utf8 with recursive array support. + * Function wp_check_invalid_utf8 with recursive array support. * * @param string|array $var Data to sanitize. * @return string|array @@ -1232,7 +1232,7 @@ function wc_format_weight( $weight ) { * @return string */ function wc_format_dimensions( $dimensions ) { - $dimension_string = implode( ' x ', array_filter( array_map( 'wc_format_localized_decimal', $dimensions ) ) ); + $dimension_string = implode( ' × ', array_filter( array_map( 'wc_format_localized_decimal', $dimensions ) ) ); if ( ! empty( $dimension_string ) ) { $dimension_string .= ' ' . get_option( 'woocommerce_dimension_unit' ); diff --git a/includes/wc-update-functions.php b/includes/wc-update-functions.php index f6e6fa2bfe7..7b0dd070c82 100644 --- a/includes/wc-update-functions.php +++ b/includes/wc-update-functions.php @@ -1855,126 +1855,6 @@ function wc_update_344_db_version() { WC_Install::update_db_version( '3.4.4' ); } -/** - * Copy order customer_id from post meta to post_author and set post_author to 0 for refunds. - * - * Two different strategies are used to copy data depending if the update is being executed from - * the command line or not. If `wp wc update` is used to update the database, this function - * copies data in a single go that is faster but uses more resources. If the databse update was - * triggered from the wp-admin, this function copies data in batches which is slower but uses - * few resources and thus is less likely to fail on smaller servers. - * - * @param WC_Background_Updater|false $updater Background updater instance or false if function is called from `wp wc update` WP-CLI command. - * @return true|void Return true if near memory limit and needs to restart. Return void if update completed. - */ -function wc_update_350_order_customer_id( $updater = false ) { - global $wpdb; - - $post_types = (array) apply_filters( 'woocommerce_update_350_order_customer_id_post_types', array( 'shop_order' ) ); - $post_types_placeholders = implode( ', ', array_fill( 0, count( $post_types ), '%s' ) ); - - if ( defined( 'WP_CLI' ) && WP_CLI ) { - // If running the update from the command-line, copy data in a single go which is faster but uses more resources. - $wpdb->query( - 'CREATE TEMPORARY TABLE customers_map (post_id BIGINT(20), customer_id BIGINT(20), PRIMARY KEY(post_id))' - ); - - $wpdb->query( - "INSERT IGNORE INTO customers_map (SELECT post_id, meta_value FROM {$wpdb->prefix}postmeta WHERE meta_key = '_customer_user')" - ); - - $wpdb->query( 'SET sql_safe_updates=1' ); - - $wpdb->query( - $wpdb->prepare( - "UPDATE {$wpdb->prefix}posts JOIN customers_map ON {$wpdb->prefix}posts.ID = customers_map.post_id SET {$wpdb->prefix}posts.post_author = customers_map.customer_id WHERE post_type IN ({$post_types_placeholders})", // phpcs:ignore WordPress.WP.PreparedSQL.NotPrepared - $post_types - ) - ); - - $wpdb->update( $wpdb->posts, array( 'post_author' => 0 ), array( 'post_type' => 'shop_order_refund' ) ); - } else { - // If running the update from the wp-admin, copy data in batches being careful not to use more memory than allowed. - $admin_orders_sql = ''; - $admin_orders = get_transient( 'wc_update_350_admin_orders' ); - - if ( false === $admin_orders ) { - // Get the list of orders that we don't want to change as they belong to user ID 1. - $admin_orders = $wpdb->get_col( - $wpdb->prepare( - "SELECT ID FROM {$wpdb->prefix}posts p - INNER JOIN {$wpdb->prefix}postmeta pm ON p.ID = pm.post_id - WHERE post_type IN ({$post_types_placeholders}) AND meta_key = '_customer_user' AND meta_value = 1", // phpcs:ignore WordPress.WP.PreparedSQL.NotPrepared - $post_types - ) - ); - - // Cache the list of orders placed by the user ID 1 as to large stores this query can be slow. - set_transient( 'wc_update_350_admin_orders', $admin_orders, DAY_IN_SECONDS ); - } - - if ( ! empty( $admin_orders ) ) { - $admin_orders_sql .= ' AND ID NOT IN (' . implode( ', ', $admin_orders ) . ') '; - } - - // Query to get a batch of orders IDs to change. - $query = $wpdb->prepare( - // phpcs:disable WordPress.WP.PreparedSQL.NotPrepared - "SELECT ID FROM {$wpdb->posts} - WHERE post_author = 1 AND post_type IN ({$post_types_placeholders}) $admin_orders_sql - LIMIT 1000", - $post_types - // phpcs:enable - ); - - while ( true ) { - // phpcs:ignore WordPress.WP.PreparedSQL.NotPrepared - $orders_to_update = $wpdb->get_col( $query ); - - // Exit loop if no more orders to update. - if ( ! $orders_to_update ) { - break; - } - - $orders_meta_data = $wpdb->get_results( - // phpcs:ignore WordPress.WP.PreparedSQL.NotPrepared - "SELECT post_id, meta_value as customer_id FROM {$wpdb->postmeta} WHERE meta_key = '_customer_user' AND post_id IN (" . implode( ', ', $orders_to_update ) . ')' - ); - - // Exit loop if no _customer_user metas exist for the list of orders to update. - if ( ! $orders_meta_data ) { - break; - } - - // Update post_author for a batch of orders. - foreach ( $orders_meta_data as $order_meta ) { - // Stop update execution and re-enqueue it if near memory limit. - if ( $updater instanceof WC_Background_Updater && $updater->is_memory_exceeded() ) { - return true; - } - - $wpdb->update( $wpdb->posts, array( 'post_author' => $order_meta->customer_id ), array( 'ID' => $order_meta->post_id ) ); - } - } - - // Set post_author to 0 instead of 1 on all shop_order_refunds. - while ( true ) { - // Stop update execution and re-enqueue it if near memory limit. - if ( $updater instanceof WC_Background_Updater && $updater->is_memory_exceeded() ) { - return true; - } - - $updated_rows = $wpdb->query( "UPDATE {$wpdb->posts} SET post_author = 0 WHERE post_type = 'shop_order_refund' LIMIT 1000" ); - - if ( ! $updated_rows ) { - break; - } - } - } - - wp_cache_flush(); -} - /** * Set the comment type to 'review' for product reviews that don't have a comment type. */ diff --git a/includes/wc-user-functions.php b/includes/wc-user-functions.php index 4dfc999153c..f8a84dfe8ed 100644 --- a/includes/wc-user-functions.php +++ b/includes/wc-user-functions.php @@ -219,15 +219,11 @@ function wc_customer_bought_product( $customer_email, $user_id, $product_id ) { $result = get_transient( $transient_name ); if ( false === $result ) { - $customer_data = array(); + $customer_data = array( $user_id ); if ( $user_id ) { $user = get_user_by( 'id', $user_id ); - if ( version_compare( get_option( 'woocommerce_db_version' ), '3.5.0', '<' ) ) { - $customer_data[] = $user_id; - } - if ( isset( $user->user_email ) ) { $customer_data[] = $user->user_email; } @@ -244,31 +240,19 @@ function wc_customer_bought_product( $customer_email, $user_id, $product_id ) { return false; } - if ( version_compare( get_option( 'woocommerce_db_version' ), '3.5.0', '>=' ) && $user_id ) { - // Since WC 3.5 wp_posts.post_author is used to store the ID of the customer who placed an order. - $query = "SELECT im.meta_value FROM {$wpdb->posts} AS p - INNER JOIN {$wpdb->postmeta} AS pm ON p.ID = pm.post_id - INNER JOIN {$wpdb->prefix}woocommerce_order_items AS i ON p.ID = i.order_id - INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS im ON i.order_item_id = im.order_item_id - WHERE p.post_status IN ( 'wc-" . implode( "','wc-", $statuses ) . "' ) - AND p.post_author = {$user_id} - AND pm.meta_key = '_billing_email' - AND im.meta_key IN ( '_product_id', '_variation_id' ) - AND im.meta_value != 0 - AND pm.meta_value IN ( '" . implode( "','", $customer_data ) . "' )"; - } else { - $query = "SELECT im.meta_value FROM {$wpdb->posts} AS p - INNER JOIN {$wpdb->postmeta} AS pm ON p.ID = pm.post_id - INNER JOIN {$wpdb->prefix}woocommerce_order_items AS i ON p.ID = i.order_id - INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS im ON i.order_item_id = im.order_item_id - WHERE p.post_status IN ( 'wc-" . implode( "','wc-", $statuses ) . "' ) - AND pm.meta_key IN ( '_billing_email', '_customer_user' ) - AND im.meta_key IN ( '_product_id', '_variation_id' ) - AND im.meta_value != 0 - AND pm.meta_value IN ( '" . implode( "','", $customer_data ) . "' )"; - } - - $result = $wpdb->get_col( $query ); // WPCS: unprepared SQL ok. + $result = $wpdb->get_col( + " + SELECT im.meta_value FROM {$wpdb->posts} AS p + INNER JOIN {$wpdb->postmeta} AS pm ON p.ID = pm.post_id + INNER JOIN {$wpdb->prefix}woocommerce_order_items AS i ON p.ID = i.order_id + INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS im ON i.order_item_id = im.order_item_id + WHERE p.post_status IN ( 'wc-" . implode( "','wc-", $statuses ) . "' ) + AND pm.meta_key IN ( '_billing_email', '_customer_user' ) + AND im.meta_key IN ( '_product_id', '_variation_id' ) + AND im.meta_value != 0 + AND pm.meta_value IN ( '" . implode( "','", $customer_data ) . "' ) + " + ); // WPCS: unprepared SQL ok. $result = array_map( 'absint', $result ); set_transient( $transient_name, $result, DAY_IN_SECONDS * 30 ); @@ -561,7 +545,7 @@ function wc_get_customer_order_count( $user_id ) { } /** - * Reset customer ID on orders when a user is deleted. + * Reset _customer_user on orders when a user is deleted. * * @param int $user_id User ID. */ @@ -574,22 +558,6 @@ function wc_reset_order_customer_id_on_deleted_user( $user_id ) { 'meta_value' => $user_id, ) ); // WPCS: slow query ok. - - $post_types = (array) apply_filters( 'woocommerce_reset_order_customer_id_post_types', array( 'shop_order' ) ); - $post_types_placeholders = implode( ', ', array_fill( 0, count( $post_types ), '%s' ) ); - $query_args = array_merge( $post_types, array( $user_id ) ); - - // Since WC 3.5, the customer ID is stored both in the _customer_user postmeta and in the post_author field. - // In future versions of WC, the plan is to use only post_author and stop using _customer_user, but for now - // we have to update both places. - $wpdb->query( - // phpcs:disable WordPress.WP.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare - $wpdb->prepare( - "UPDATE {$wpdb->posts} SET `post_author` = 0 WHERE post_type IN ({$post_types_placeholders}) AND post_author = %d", - $query_args - ) - // phpcs:enable - ); } add_action( 'deleted_user', 'wc_reset_order_customer_id_on_deleted_user' ); diff --git a/includes/wc-webhook-functions.php b/includes/wc-webhook-functions.php index 23361fb976c..0a2b808099e 100644 --- a/includes/wc-webhook-functions.php +++ b/includes/wc-webhook-functions.php @@ -21,7 +21,10 @@ function wc_webhook_process_delivery( $webhook, $arg ) { // user who triggered it. if ( apply_filters( 'woocommerce_webhook_deliver_async', true, $webhook, $arg ) ) { // Deliver in background. - WC()->queue()->add( 'woocommerce_deliver_webhook_async', array( 'webhook_id' => $webhook->get_id(), 'arg' => $arg ), 'woocommerce-webhooks' ); + WC()->queue()->add( 'woocommerce_deliver_webhook_async', array( + 'webhook_id' => $webhook->get_id(), + 'arg' => $arg, + ), 'woocommerce-webhooks' ); } else { // Deliver immediately. $webhook->deliver( $arg ); @@ -124,3 +127,17 @@ function wc_get_webhook( $id ) { return 0 !== $webhook->get_id() ? $webhook : null; } + +/** + * Get webhoook REST API versions. + * + * @since 3.5.1 + * @return array + */ +function wc_get_webhook_rest_api_versions() { + return array( + 'wp_api_v1', + 'wp_api_v2', + 'wp_api_v3', + ); +} diff --git a/readme.txt b/readme.txt index 60b869da06c..013bedcce6c 100644 --- a/readme.txt +++ b/readme.txt @@ -3,7 +3,7 @@ Contributors: automattic, mikejolley, jameskoster, claudiosanches, claudiulodro, Tags: ecommerce, e-commerce, store, sales, sell, shop, cart, checkout, downloadable, downloads, paypal, storefront, woo commerce Requires at least: 4.7 Tested up to: 4.9 -Stable tag: 3.4.5 +Stable tag: 3.5.0 License: GPLv3 License URI: https://www.gnu.org/licenses/gpl-3.0.html diff --git a/templates/emails/admin-new-order.php b/templates/emails/admin-new-order.php index dd9d7adf4ea..11c3a5d0c0e 100644 --- a/templates/emails/admin-new-order.php +++ b/templates/emails/admin-new-order.php @@ -46,9 +46,6 @@ do_action( 'woocommerce_email_order_meta', $order, $sent_to_admin, $plain_text, * @hooked WC_Emails::email_address() Shows email address */ do_action( 'woocommerce_email_customer_details', $order, $sent_to_admin, $plain_text, $email ); -?> -

-assertEquals( '10 x 10 x 10 cm', wc_format_dimensions( array( 10, 10, 10 ) ) ); + $this->assertEquals( '10 × 10 × 10 cm', wc_format_dimensions( array( 10, 10, 10 ) ) ); } /** diff --git a/tests/unit-tests/util/class-wc-tests-core-functions.php b/tests/unit-tests/util/class-wc-tests-core-functions.php index 2b4bf34fc0a..8e0f3532fcd 100644 --- a/tests/unit-tests/util/class-wc-tests-core-functions.php +++ b/tests/unit-tests/util/class-wc-tests-core-functions.php @@ -849,4 +849,25 @@ class WC_Tests_Core_Functions extends WC_Unit_Test_Case { $_SERVER['HTTP_USER_AGENT'] = $example_user_agent; $this->assertEquals( $example_user_agent, wc_get_user_agent() ); } + + /** + * Test the wc_checkout_fields_uasort_comparison function. + * + * @return void + */ + public function test_wc_checkout_fields_uasort_comparison() { + $fields = array( + 'billing_first_name' => array( + 'priority' => 10, + ), + 'billing_last_name' => array( + 'priority' => 20, + ), + 'billing_email' => array( + 'priority' => 1, + ), + ); + uasort( $fields, 'wc_checkout_fields_uasort_comparison' ); + $this->assertSame( 0, array_search( 'billing_email', array_keys( $fields ) ) ); + } } diff --git a/woocommerce.php b/woocommerce.php index 728fc0b829d..a9edb396706 100644 --- a/woocommerce.php +++ b/woocommerce.php @@ -3,7 +3,7 @@ * Plugin Name: WooCommerce * Plugin URI: https://woocommerce.com/ * Description: An eCommerce toolkit that helps you sell anything. Beautifully. - * Version: 3.5.0-rc.1 + * Version: 3.6.0-dev * Author: Automattic * Author URI: https://woocommerce.com * Text Domain: woocommerce