Merged in feature/MAW-855-import-code-into-aws (pull request #2)
code import from pantheon * code import from pantheon
This commit is contained in:
@@ -195,6 +195,19 @@ abstract class WC_Data {
|
||||
* @return bool result
|
||||
*/
|
||||
public function delete( $force_delete = false ) {
|
||||
/**
|
||||
* Filters whether an object deletion should take place. Equivalent to `pre_delete_post`.
|
||||
*
|
||||
* @param mixed $check Whether to go ahead with deletion.
|
||||
* @param WC_Data $this The data object being deleted.
|
||||
* @param bool $force_delete Whether to bypass the trash.
|
||||
*
|
||||
* @since 8.1.0.
|
||||
*/
|
||||
$check = apply_filters( "woocommerce_pre_delete_$this->object_type", null, $this, $force_delete );
|
||||
if ( null !== $check ) {
|
||||
return $check;
|
||||
}
|
||||
if ( $this->data_store ) {
|
||||
$this->data_store->delete( $this, array( 'force_delete' => $force_delete ) );
|
||||
$this->set_id( 0 );
|
||||
@@ -671,14 +684,44 @@ abstract class WC_Data {
|
||||
if ( is_null( $meta->value ) ) {
|
||||
if ( ! empty( $meta->id ) ) {
|
||||
$this->data_store->delete_meta( $this, $meta );
|
||||
/**
|
||||
* Fires immediately after deleting metadata.
|
||||
*
|
||||
* @param int $meta_id ID of deleted metadata entry.
|
||||
* @param int $object_id Object ID.
|
||||
* @param string $meta_key Metadata key.
|
||||
* @param mixed $meta_value Metadata value (will be empty for delete).
|
||||
*/
|
||||
do_action( "deleted_{$this->object_type}_meta", $meta->id, $this->get_id(), $meta->key, $meta->value );
|
||||
|
||||
unset( $this->meta_data[ $array_key ] );
|
||||
}
|
||||
} elseif ( empty( $meta->id ) ) {
|
||||
$meta->id = $this->data_store->add_meta( $this, $meta );
|
||||
/**
|
||||
* Fires immediately after adding metadata.
|
||||
*
|
||||
* @param int $meta_id ID of added metadata entry.
|
||||
* @param int $object_id Object ID.
|
||||
* @param string $meta_key Metadata key.
|
||||
* @param mixed $meta_value Metadata value.
|
||||
*/
|
||||
do_action( "added_{$this->object_type}_meta", $meta->id, $this->get_id(), $meta->key, $meta->value );
|
||||
|
||||
$meta->apply_changes();
|
||||
} else {
|
||||
if ( $meta->get_changes() ) {
|
||||
$this->data_store->update_meta( $this, $meta );
|
||||
/**
|
||||
* Fires immediately after updating metadata.
|
||||
*
|
||||
* @param int $meta_id ID of updated metadata entry.
|
||||
* @param int $object_id Object ID.
|
||||
* @param string $meta_key Metadata key.
|
||||
* @param mixed $meta_value Metadata value.
|
||||
*/
|
||||
do_action( "updated_{$this->object_type}_meta", $meta->id, $this->get_id(), $meta->key, $meta->value );
|
||||
|
||||
$meta->apply_changes();
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -376,7 +376,7 @@ abstract class WC_Payment_Gateway extends WC_Settings_API {
|
||||
* @param int $order_id Order ID.
|
||||
* @param float|null $amount Refund amount.
|
||||
* @param string $reason Refund reason.
|
||||
* @return boolean True or false based on success, or a WP_Error object.
|
||||
* @return bool|\WP_Error True or false based on success, or a WP_Error object.
|
||||
*/
|
||||
public function process_refund( $order_id, $amount = null, $reason = '' ) {
|
||||
return false;
|
||||
|
||||
@@ -64,8 +64,24 @@ class WC_Admin_Addons {
|
||||
* @return void
|
||||
*/
|
||||
public static function render_featured() {
|
||||
$featured = self::fetch_featured();
|
||||
|
||||
if ( is_wp_error( $featured ) ) {
|
||||
self::output_empty( $featured->get_error_message() );
|
||||
}
|
||||
|
||||
self::output_featured( $featured );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch featured products from WCCOM's the Featured 2.0 Endpoint and cache the data for a day.
|
||||
*
|
||||
* @return array|WP_Error
|
||||
*/
|
||||
public static function fetch_featured() {
|
||||
$locale = get_user_locale();
|
||||
$featured = self::get_locale_data_from_transient( 'wc_addons_featured', $locale );
|
||||
|
||||
if ( false === $featured ) {
|
||||
$headers = array();
|
||||
$auth = WC_Helper_Options::get( 'auth' );
|
||||
@@ -96,9 +112,7 @@ class WC_Admin_Addons {
|
||||
? __( 'We encountered an SSL error. Please ensure your site supports TLS version 1.2 or above.', 'woocommerce' )
|
||||
: $raw_featured->get_error_message();
|
||||
|
||||
self::output_empty( $message );
|
||||
|
||||
return;
|
||||
return new WP_Error( 'wc-addons-connection-error', $message );
|
||||
}
|
||||
|
||||
$response_code = (int) wp_remote_retrieve_response_code( $raw_featured );
|
||||
@@ -117,18 +131,15 @@ class WC_Admin_Addons {
|
||||
$response_code
|
||||
);
|
||||
|
||||
self::output_empty( $message );
|
||||
|
||||
return;
|
||||
return new WP_Error( 'wc-addons-connection-error', $message );
|
||||
}
|
||||
|
||||
$featured = json_decode( wp_remote_retrieve_body( $raw_featured ) );
|
||||
if ( empty( $featured ) || ! is_array( $featured ) ) {
|
||||
do_action( 'woocommerce_page_wc-addons_connection_error', 'Empty or malformed response' );
|
||||
$message = __( 'Our request to the featured API got a malformed response.', 'woocommerce' );
|
||||
self::output_empty( $message );
|
||||
|
||||
return;
|
||||
return new WP_Error( 'wc-addons-connection-error', $message );
|
||||
}
|
||||
|
||||
if ( $featured ) {
|
||||
@@ -136,7 +147,7 @@ class WC_Admin_Addons {
|
||||
}
|
||||
}
|
||||
|
||||
self::output_featured( $featured );
|
||||
return $featured;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -340,7 +351,7 @@ class WC_Admin_Addons {
|
||||
$url
|
||||
);
|
||||
|
||||
echo '<a href="' . esc_url( $url ) . '" class="add-new-h2">' . esc_html( $text ) . '</a>' . "\n";
|
||||
echo '<a href="' . esc_url( $url ) . '" class="page-title-action">' . esc_html( $text ) . '</a>' . "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -96,7 +96,7 @@ class WC_Admin_API_Keys {
|
||||
private static function table_list_output() {
|
||||
global $wpdb, $keys_table_list;
|
||||
|
||||
echo '<h2 class="wc-table-list-header">' . esc_html__( 'REST API', 'woocommerce' ) . ' <a href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=advanced§ion=keys&create-key=1' ) ) . '" class="add-new-h2">' . esc_html__( 'Add key', 'woocommerce' ) . '</a></h2>';
|
||||
echo '<h2 class="wc-table-list-header">' . esc_html__( 'REST API', 'woocommerce' ) . ' <a href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=advanced§ion=keys&create-key=1' ) ) . '" class="page-title-action">' . esc_html__( 'Add key', 'woocommerce' ) . '</a></h2>';
|
||||
|
||||
// Get the API keys count.
|
||||
$count = $wpdb->get_var( "SELECT COUNT(key_id) FROM {$wpdb->prefix}woocommerce_api_keys WHERE 1 = 1;" );
|
||||
|
||||
@@ -368,74 +368,77 @@ if ( ! class_exists( 'WC_Admin_Assets', false ) ) :
|
||||
}
|
||||
|
||||
$params = array(
|
||||
'remove_item_notice' => $remove_item_notice,
|
||||
'remove_fee_notice' => $remove_fee_notice,
|
||||
'remove_shipping_notice' => $remove_shipping_notice,
|
||||
'i18n_select_items' => __( 'Please select some items.', 'woocommerce' ),
|
||||
'i18n_do_refund' => __( 'Are you sure you wish to process this refund? This action cannot be undone.', 'woocommerce' ),
|
||||
'i18n_delete_refund' => __( 'Are you sure you wish to delete this refund? This action cannot be undone.', 'woocommerce' ),
|
||||
'i18n_delete_tax' => __( 'Are you sure you wish to delete this tax column? This action cannot be undone.', 'woocommerce' ),
|
||||
'remove_item_meta' => __( 'Remove this item meta?', 'woocommerce' ),
|
||||
'name_label' => __( 'Name', 'woocommerce' ),
|
||||
'remove_label' => __( 'Remove', 'woocommerce' ),
|
||||
'click_to_toggle' => __( 'Click to toggle', 'woocommerce' ),
|
||||
'values_label' => __( 'Value(s)', 'woocommerce' ),
|
||||
'text_attribute_tip' => __( 'Enter some text, or some attributes by pipe (|) separating values.', 'woocommerce' ),
|
||||
'visible_label' => __( 'Visible on the product page', 'woocommerce' ),
|
||||
'used_for_variations_label' => __( 'Used for variations', 'woocommerce' ),
|
||||
'new_attribute_prompt' => __( 'Enter a name for the new attribute term:', 'woocommerce' ),
|
||||
'calc_totals' => __( 'Recalculate totals? This will calculate taxes based on the customers country (or the store base country) and update totals.', 'woocommerce' ),
|
||||
'copy_billing' => __( 'Copy billing information to shipping information? This will remove any currently entered shipping information.', 'woocommerce' ),
|
||||
'load_billing' => __( "Load the customer's billing information? This will remove any currently entered billing information.", 'woocommerce' ),
|
||||
'load_shipping' => __( "Load the customer's shipping information? This will remove any currently entered shipping information.", 'woocommerce' ),
|
||||
'featured_label' => __( 'Featured', 'woocommerce' ),
|
||||
'prices_include_tax' => esc_attr( get_option( 'woocommerce_prices_include_tax' ) ),
|
||||
'tax_based_on' => esc_attr( get_option( 'woocommerce_tax_based_on' ) ),
|
||||
'round_at_subtotal' => esc_attr( get_option( 'woocommerce_tax_round_at_subtotal' ) ),
|
||||
'no_customer_selected' => __( 'No customer selected', 'woocommerce' ),
|
||||
'plugin_url' => WC()->plugin_url(),
|
||||
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
||||
'order_item_nonce' => wp_create_nonce( 'order-item' ),
|
||||
'add_attribute_nonce' => wp_create_nonce( 'add-attribute' ),
|
||||
'save_attributes_nonce' => wp_create_nonce( 'save-attributes' ),
|
||||
'add_attributes_and_variations' => wp_create_nonce( 'add-attributes-and-variations' ),
|
||||
'calc_totals_nonce' => wp_create_nonce( 'calc-totals' ),
|
||||
'get_customer_details_nonce' => wp_create_nonce( 'get-customer-details' ),
|
||||
'search_products_nonce' => wp_create_nonce( 'search-products' ),
|
||||
'grant_access_nonce' => wp_create_nonce( 'grant-access' ),
|
||||
'revoke_access_nonce' => wp_create_nonce( 'revoke-access' ),
|
||||
'add_order_note_nonce' => wp_create_nonce( 'add-order-note' ),
|
||||
'delete_order_note_nonce' => wp_create_nonce( 'delete-order-note' ),
|
||||
'calendar_image' => WC()->plugin_url() . '/assets/images/calendar.png',
|
||||
'post_id' => $this->is_order_meta_box_screen( $screen_id ) && isset( $order_or_post_object ) ? \Automattic\WooCommerce\Utilities\OrderUtil::get_post_or_order_id( $order_or_post_object ) : $post_id,
|
||||
'base_country' => WC()->countries->get_base_country(),
|
||||
'currency_format_num_decimals' => wc_get_price_decimals(),
|
||||
'currency_format_symbol' => get_woocommerce_currency_symbol( $currency ),
|
||||
'currency_format_decimal_sep' => esc_attr( wc_get_price_decimal_separator() ),
|
||||
'currency_format_thousand_sep' => esc_attr( wc_get_price_thousand_separator() ),
|
||||
'currency_format' => esc_attr( str_replace( array( '%1$s', '%2$s' ), array( '%s', '%v' ), get_woocommerce_price_format() ) ), // For accounting JS.
|
||||
'rounding_precision' => wc_get_rounding_precision(),
|
||||
'tax_rounding_mode' => wc_get_tax_rounding_mode(),
|
||||
'product_types' => array_unique( array_merge( array( 'simple', 'grouped', 'variable', 'external' ), array_keys( wc_get_product_types() ) ) ),
|
||||
'i18n_download_permission_fail' => __( 'Could not grant access - the user may already have permission for this file or billing email is not set. Ensure the billing email is set, and the order has been saved.', 'woocommerce' ),
|
||||
'i18n_permission_revoke' => __( 'Are you sure you want to revoke access to this download?', 'woocommerce' ),
|
||||
'i18n_tax_rate_already_exists' => __( 'You cannot add the same tax rate twice!', 'woocommerce' ),
|
||||
'i18n_delete_note' => __( 'Are you sure you wish to delete this note? This action cannot be undone.', 'woocommerce' ),
|
||||
'i18n_apply_coupon' => __( 'Enter a coupon code to apply. Discounts are applied to line totals, before taxes.', 'woocommerce' ),
|
||||
'i18n_add_fee' => __( 'Enter a fixed amount or percentage to apply as a fee.', 'woocommerce' ),
|
||||
'i18n_attribute_name_placeholder' => __( 'New attribute', 'woocommerce' ),
|
||||
'i18n_product_simple_tip' => __( '<b>Simple –</b> covers the vast majority of any products you may sell. Simple products are shipped and have no options. For example, a book.', 'woocommerce' ),
|
||||
'i18n_product_grouped_tip' => __( '<b>Grouped –</b> a collection of related products that can be purchased individually and only consist of simple products. For example, a set of six drinking glasses.', 'woocommerce' ),
|
||||
'i18n_product_external_tip' => __( '<b>External or Affiliate –</b> one that you list and describe on your website but is sold elsewhere.', 'woocommerce' ),
|
||||
'i18n_product_variable_tip' => __( '<b>Variable –</b> a product with variations, each of which may have a different SKU, price, stock option, etc. For example, a t-shirt available in different colors and/or sizes.', 'woocommerce' ),
|
||||
'i18n_product_other_tip' => __( 'Product types define available product details and attributes, such as downloadable files and variations. They’re also used for analytics and inventory management.', 'woocommerce' ),
|
||||
'i18n_product_description_tip' => __( 'Describe this product. What makes it unique? What are its most important features?', 'woocommerce' ),
|
||||
'i18n_product_short_description_tip' => __( 'Summarize this product in 1-2 short sentences. We’ll show it at the top of the page.', 'woocommerce' ),
|
||||
'i18n_save_attribute_variation_tip' => __( 'Make sure you enter the name and values for each attribute.', 'woocommerce' ),
|
||||
'remove_item_notice' => $remove_item_notice,
|
||||
'remove_fee_notice' => $remove_fee_notice,
|
||||
'remove_shipping_notice' => $remove_shipping_notice,
|
||||
'i18n_select_items' => __( 'Please select some items.', 'woocommerce' ),
|
||||
'i18n_do_refund' => __( 'Are you sure you wish to process this refund? This action cannot be undone.', 'woocommerce' ),
|
||||
'i18n_delete_refund' => __( 'Are you sure you wish to delete this refund? This action cannot be undone.', 'woocommerce' ),
|
||||
'i18n_delete_tax' => __( 'Are you sure you wish to delete this tax column? This action cannot be undone.', 'woocommerce' ),
|
||||
'remove_item_meta' => __( 'Remove this item meta?', 'woocommerce' ),
|
||||
'name_label' => __( 'Name', 'woocommerce' ),
|
||||
'remove_label' => __( 'Remove', 'woocommerce' ),
|
||||
'click_to_toggle' => __( 'Click to toggle', 'woocommerce' ),
|
||||
'values_label' => __( 'Value(s)', 'woocommerce' ),
|
||||
'text_attribute_tip' => __( 'Enter some text, or some attributes by pipe (|) separating values.', 'woocommerce' ),
|
||||
'visible_label' => __( 'Visible on the product page', 'woocommerce' ),
|
||||
'used_for_variations_label' => __( 'Used for variations', 'woocommerce' ),
|
||||
'new_attribute_prompt' => __( 'Enter a name for the new attribute term:', 'woocommerce' ),
|
||||
'calc_totals' => __( 'Recalculate totals? This will calculate taxes based on the customers country (or the store base country) and update totals.', 'woocommerce' ),
|
||||
'copy_billing' => __( 'Copy billing information to shipping information? This will remove any currently entered shipping information.', 'woocommerce' ),
|
||||
'load_billing' => __( "Load the customer's billing information? This will remove any currently entered billing information.", 'woocommerce' ),
|
||||
'load_shipping' => __( "Load the customer's shipping information? This will remove any currently entered shipping information.", 'woocommerce' ),
|
||||
'featured_label' => __( 'Featured', 'woocommerce' ),
|
||||
'prices_include_tax' => esc_attr( get_option( 'woocommerce_prices_include_tax' ) ),
|
||||
'tax_based_on' => esc_attr( get_option( 'woocommerce_tax_based_on' ) ),
|
||||
'round_at_subtotal' => esc_attr( get_option( 'woocommerce_tax_round_at_subtotal' ) ),
|
||||
'no_customer_selected' => __( 'No customer selected', 'woocommerce' ),
|
||||
'plugin_url' => WC()->plugin_url(),
|
||||
'ajax_url' => admin_url( 'admin-ajax.php' ),
|
||||
'order_item_nonce' => wp_create_nonce( 'order-item' ),
|
||||
'add_attribute_nonce' => wp_create_nonce( 'add-attribute' ),
|
||||
'save_attributes_nonce' => wp_create_nonce( 'save-attributes' ),
|
||||
'add_attributes_and_variations' => wp_create_nonce( 'add-attributes-and-variations' ),
|
||||
'calc_totals_nonce' => wp_create_nonce( 'calc-totals' ),
|
||||
'get_customer_details_nonce' => wp_create_nonce( 'get-customer-details' ),
|
||||
'search_products_nonce' => wp_create_nonce( 'search-products' ),
|
||||
'grant_access_nonce' => wp_create_nonce( 'grant-access' ),
|
||||
'revoke_access_nonce' => wp_create_nonce( 'revoke-access' ),
|
||||
'add_order_note_nonce' => wp_create_nonce( 'add-order-note' ),
|
||||
'delete_order_note_nonce' => wp_create_nonce( 'delete-order-note' ),
|
||||
'calendar_image' => WC()->plugin_url() . '/assets/images/calendar.png',
|
||||
'post_id' => $this->is_order_meta_box_screen( $screen_id ) && isset( $order_or_post_object ) ? \Automattic\WooCommerce\Utilities\OrderUtil::get_post_or_order_id( $order_or_post_object ) : $post_id,
|
||||
'base_country' => WC()->countries->get_base_country(),
|
||||
'currency_format_num_decimals' => wc_get_price_decimals(),
|
||||
'currency_format_symbol' => get_woocommerce_currency_symbol( $currency ),
|
||||
'currency_format_decimal_sep' => esc_attr( wc_get_price_decimal_separator() ),
|
||||
'currency_format_thousand_sep' => esc_attr( wc_get_price_thousand_separator() ),
|
||||
'currency_format' => esc_attr( str_replace( array( '%1$s', '%2$s' ), array( '%s', '%v' ), get_woocommerce_price_format() ) ), // For accounting JS.
|
||||
'rounding_precision' => wc_get_rounding_precision(),
|
||||
'tax_rounding_mode' => wc_get_tax_rounding_mode(),
|
||||
'product_types' => array_unique( array_merge( array( 'simple', 'grouped', 'variable', 'external' ), array_keys( wc_get_product_types() ) ) ),
|
||||
'i18n_download_permission_fail' => __( 'Could not grant access - the user may already have permission for this file or billing email is not set. Ensure the billing email is set, and the order has been saved.', 'woocommerce' ),
|
||||
'i18n_permission_revoke' => __( 'Are you sure you want to revoke access to this download?', 'woocommerce' ),
|
||||
'i18n_tax_rate_already_exists' => __( 'You cannot add the same tax rate twice!', 'woocommerce' ),
|
||||
'i18n_delete_note' => __( 'Are you sure you wish to delete this note? This action cannot be undone.', 'woocommerce' ),
|
||||
'i18n_apply_coupon' => __( 'Enter a coupon code to apply. Discounts are applied to line totals, before taxes.', 'woocommerce' ),
|
||||
'i18n_add_fee' => __( 'Enter a fixed amount or percentage to apply as a fee.', 'woocommerce' ),
|
||||
'i18n_attribute_name_placeholder' => __( 'New attribute', 'woocommerce' ),
|
||||
'i18n_product_simple_tip' => __( '<b>Simple –</b> covers the vast majority of any products you may sell. Simple products are shipped and have no options. For example, a book.', 'woocommerce' ),
|
||||
'i18n_product_grouped_tip' => __( '<b>Grouped –</b> a collection of related products that can be purchased individually and only consist of simple products. For example, a set of six drinking glasses.', 'woocommerce' ),
|
||||
'i18n_product_external_tip' => __( '<b>External or Affiliate –</b> one that you list and describe on your website but is sold elsewhere.', 'woocommerce' ),
|
||||
'i18n_product_variable_tip' => __( '<b>Variable –</b> a product with variations, each of which may have a different SKU, price, stock option, etc. For example, a t-shirt available in different colors and/or sizes.', 'woocommerce' ),
|
||||
'i18n_product_other_tip' => __( 'Product types define available product details and attributes, such as downloadable files and variations. They’re also used for analytics and inventory management.', 'woocommerce' ),
|
||||
'i18n_product_description_tip' => __( 'Describe this product. What makes it unique? What are its most important features?', 'woocommerce' ),
|
||||
'i18n_product_short_description_tip' => __( 'Summarize this product in 1-2 short sentences. We’ll show it at the top of the page.', 'woocommerce' ),
|
||||
'i18n_save_attribute_variation_tip' => __( 'Make sure you enter the name and values for each attribute.', 'woocommerce' ),
|
||||
/* translators: %1$s: maximum file size */
|
||||
'i18n_product_image_tip' => sprintf( __( 'For best results, upload JPEG or PNG files that are 1000 by 1000 pixels or larger. Maximum upload file size: %1$s.', 'woocommerce' ) , size_format( wp_max_upload_size() ) ),
|
||||
'i18n_product_image_tip' => sprintf( __( 'For best results, upload JPEG or PNG files that are 1000 by 1000 pixels or larger. Maximum upload file size: %1$s.', 'woocommerce' ), size_format( wp_max_upload_size() ) ),
|
||||
'i18n_remove_used_attribute_confirmation_message' => __( 'If you remove this attribute, customers will no longer be able to purchase some variations of this product.', 'woocommerce' ),
|
||||
'i18n_add_attribute_error_notice' => __( 'Adding new attribute failed.', 'woocommerce' ),
|
||||
'i18n_add_attribute_error_notice' => __( 'Adding new attribute failed.', 'woocommerce' ),
|
||||
/* translators: %s: WC_DELIMITER */
|
||||
'i18n_attributes_default_placeholder' => sprintf( esc_attr__( 'Enter some descriptive text. Use “%s” to separate different values.', 'woocommerce' ), esc_attr( WC_DELIMITER ) ),
|
||||
'i18n_attributes_used_for_variations_placeholder' => sprintf( esc_attr__( 'Enter options for customers to choose from, f.e. “Blue” or “Large”. Use “%s” to separate different options.', 'woocommerce' ), esc_attr( WC_DELIMITER ) )
|
||||
);
|
||||
|
||||
wp_localize_script( 'wc-admin-meta-boxes', 'woocommerce_admin_meta_boxes', $params );
|
||||
@@ -549,7 +552,6 @@ if ( ! class_exists( 'WC_Admin_Assets', false ) ) :
|
||||
);
|
||||
wp_enqueue_script( 'marketplace-suggestions' );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -76,7 +76,7 @@ class WC_Admin_Help {
|
||||
'<p><a href="https://woocommerce.com/?utm_source=helptab&utm_medium=product&utm_content=about&utm_campaign=woocommerceplugin" target="_blank">' . __( 'About WooCommerce', 'woocommerce' ) . '</a></p>' .
|
||||
'<p><a href="https://wordpress.org/plugins/woocommerce/" target="_blank">' . __( 'WordPress.org project', 'woocommerce' ) . '</a></p>' .
|
||||
'<p><a href="https://github.com/woocommerce/woocommerce/" target="_blank">' . __( 'GitHub project', 'woocommerce' ) . '</a></p>' .
|
||||
'<p><a href="https://woocommerce.com/storefront/?utm_source=helptab&utm_medium=product&utm_content=wcthemes&utm_campaign=woocommerceplugin" target="_blank">' . __( 'Official theme', 'woocommerce' ) . '</a></p>' .
|
||||
'<p><a href="https://woocommerce.com/product-category/themes/?utm_source=helptab&utm_medium=product&utm_content=wcthemes&utm_campaign=woocommerceplugin" target="_blank">' . __( 'Official themes', 'woocommerce' ) . '</a></p>' .
|
||||
'<p><a href="https://woocommerce.com/product-category/woocommerce-extensions/?utm_source=helptab&utm_medium=product&utm_content=wcextensions&utm_campaign=woocommerceplugin" target="_blank">' . __( 'Official extensions', 'woocommerce' ) . '</a></p>'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,10 +6,14 @@
|
||||
* @version 2.5.0
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\Admin\Features\Features;
|
||||
use Automattic\WooCommerce\Admin\PageController;
|
||||
use Automattic\WooCommerce\Internal\Admin\Marketplace;
|
||||
use Automattic\WooCommerce\Internal\Admin\Orders\COTRedirectionController;
|
||||
use Automattic\WooCommerce\Internal\Admin\Orders\PageController as Custom_Orders_PageController;
|
||||
use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
|
||||
use Automattic\WooCommerce\Internal\DataStores\Orders\CustomOrdersTableController;
|
||||
use Automattic\WooCommerce\Admin\Features\Features;
|
||||
use Automattic\WooCommerce\Utilities\FeaturesUtil;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
@@ -22,6 +26,13 @@ if ( class_exists( 'WC_Admin_Menus', false ) ) {
|
||||
*/
|
||||
class WC_Admin_Menus {
|
||||
|
||||
/**
|
||||
* The CSS classes used to hide the submenu items in navigation.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const HIDE_CSS_CLASS = 'hide-if-js';
|
||||
|
||||
/**
|
||||
* Hook in tabs.
|
||||
*/
|
||||
@@ -36,8 +47,23 @@ class WC_Admin_Menus {
|
||||
add_action( 'admin_menu', array( $this, 'settings_menu' ), 50 );
|
||||
add_action( 'admin_menu', array( $this, 'status_menu' ), 60 );
|
||||
|
||||
/**
|
||||
* Controls whether we add a submenu item for the WooCommerce Addons page.
|
||||
* Woo Express uses this filter.
|
||||
*
|
||||
* @since 8.2.1
|
||||
*
|
||||
* @param bool $show_addons_page If the addons page should be included.
|
||||
*/
|
||||
if ( apply_filters( 'woocommerce_show_addons_page', true ) ) {
|
||||
add_action( 'admin_menu', array( $this, 'addons_menu' ), 70 );
|
||||
if ( FeaturesUtil::feature_is_enabled( 'marketplace' ) ) {
|
||||
$container = wc_get_container();
|
||||
$container->get( Marketplace::class );
|
||||
|
||||
add_action( 'admin_menu', array( $this, 'addons_my_subscriptions' ), 70 );
|
||||
} else {
|
||||
add_action( 'admin_menu', array( $this, 'addons_menu' ), 70 );
|
||||
}
|
||||
}
|
||||
|
||||
add_filter( 'menu_order', array( $this, 'menu_order' ) );
|
||||
@@ -171,6 +197,18 @@ class WC_Admin_Menus {
|
||||
add_submenu_page( 'woocommerce', __( 'WooCommerce extensions', 'woocommerce' ), $menu_title, 'manage_woocommerce', 'wc-addons', array( $this, 'addons_page' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the wc-addons page within the WooCommerce menu.
|
||||
* Temporary measure till we convert the whole page to React.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addons_my_subscriptions() {
|
||||
add_submenu_page( 'woocommerce', __( 'WooCommerce extensions', 'woocommerce' ), null, 'manage_woocommerce', 'wc-addons', array( $this, 'addons_page' ) );
|
||||
// Temporarily hide the submenu item we've just added.
|
||||
$this->hide_submenu_page( 'woocommerce', 'wc-addons' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlights the correct top level admin menu item for post type add screens.
|
||||
*/
|
||||
@@ -426,7 +464,7 @@ class WC_Admin_Menus {
|
||||
* Maybe add new management product experience.
|
||||
*/
|
||||
public function maybe_add_new_product_management_experience() {
|
||||
if ( Features::is_enabled( 'new-product-management-experience' ) || \Automattic\WooCommerce\Utilities\FeaturesUtil::feature_is_enabled( 'product_block_editor' ) ) {
|
||||
if ( Features::is_enabled( 'new-product-management-experience' ) || FeaturesUtil::feature_is_enabled( 'product_block_editor' ) ) {
|
||||
global $submenu;
|
||||
if ( isset( $submenu['edit.php?post_type=product'][10] ) ) {
|
||||
// Disable phpcs since we need to override submenu classes.
|
||||
@@ -437,6 +475,58 @@ class WC_Admin_Menus {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the submenu page based on slug and return the item that was hidden.
|
||||
*
|
||||
* Borrowed from Jetpack's Base_Admin_Menu class.
|
||||
*
|
||||
* Instead of actually removing the submenu item, a safer approach is to hide it and filter it in the API response.
|
||||
* In this manner we'll avoid breaking third-party plugins depending on items that no longer exist.
|
||||
*
|
||||
* A false|array value is returned to be consistent with remove_submenu_page() function
|
||||
*
|
||||
* @param string $menu_slug The parent menu slug.
|
||||
* @param string $submenu_slug The submenu slug that should be hidden.
|
||||
* @return false|array
|
||||
*/
|
||||
public function hide_submenu_page( $menu_slug, $submenu_slug ) {
|
||||
global $submenu;
|
||||
|
||||
if ( ! isset( $submenu[ $menu_slug ] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ( $submenu[ $menu_slug ] as $i => $item ) {
|
||||
if ( $submenu_slug !== $item[2] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$this->hide_submenu_element( $i, $menu_slug, $item );
|
||||
|
||||
return $item;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply the hide-if-js CSS class to a submenu item.
|
||||
*
|
||||
* Borrowed from Jetpack's Base_Admin_Menu class.
|
||||
*
|
||||
* @param int $index The position of a submenu item in the submenu array.
|
||||
* @param string $parent_slug The parent slug.
|
||||
* @param array $item The submenu item.
|
||||
*/
|
||||
public function hide_submenu_element( $index, $parent_slug, $item ) {
|
||||
global $submenu;
|
||||
|
||||
$css_classes = empty( $item[4] ) ? self::HIDE_CSS_CLASS : $item[4] . ' ' . self::HIDE_CSS_CLASS;
|
||||
|
||||
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
|
||||
$submenu [ $parent_slug ][ $index ][4] = $css_classes;
|
||||
}
|
||||
}
|
||||
|
||||
return new WC_Admin_Menus();
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Internal\Admin\Orders\Edit as OrderEdit;
|
||||
use Automattic\WooCommerce\Utilities\OrderUtil;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
@@ -215,7 +216,7 @@ class WC_Admin_Meta_Boxes {
|
||||
$post_id = absint( $post_id );
|
||||
|
||||
// $post_id and $post are required
|
||||
if ( empty( $post_id ) || empty( $post ) || self::$saved_meta_boxes ) {
|
||||
if ( empty( $post_id ) || empty( $post ) || ! is_a( $post, 'WP_Post' ) || self::$saved_meta_boxes ) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -247,6 +248,10 @@ class WC_Admin_Meta_Boxes {
|
||||
|
||||
// Check the post type.
|
||||
if ( in_array( $post->post_type, wc_get_order_types( 'order-meta-boxes' ), true ) ) {
|
||||
if ( OrderUtil::custom_orders_table_usage_is_enabled() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save meta for shop order.
|
||||
*
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
*/
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Internal\Utilities\Users;
|
||||
use Automattic\WooCommerce\Internal\Traits\AccessiblePrivateMethods;
|
||||
use Automattic\WooCommerce\Internal\Utilities\Users;
|
||||
use Automattic\WooCommerce\Internal\Utilities\WebhookUtil;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
@@ -39,7 +40,6 @@ class WC_Admin_Notices {
|
||||
'regenerating_thumbnails' => 'regenerating_thumbnails_notice',
|
||||
'regenerating_lookup_table' => 'regenerating_lookup_table_notice',
|
||||
'no_secure_connection' => 'secure_connection_notice',
|
||||
WC_PHP_MIN_REQUIREMENTS_NOTICE => 'wp_php_min_requirements_notice',
|
||||
'maxmind_license_key' => 'maxmind_missing_license_key_notice',
|
||||
'redirect_download_method' => 'redirect_download_method_notice',
|
||||
'uploads_directory_is_unprotected' => 'uploads_directory_is_unprotected_notice',
|
||||
@@ -57,7 +57,7 @@ class WC_Admin_Notices {
|
||||
add_action( 'woocommerce_installed', array( __CLASS__, 'reset_admin_notices' ) );
|
||||
add_action( 'wp_loaded', array( __CLASS__, 'add_redirect_download_method_notice' ) );
|
||||
add_action( 'admin_init', array( __CLASS__, 'hide_notices' ), 20 );
|
||||
self::add_action( 'admin_init', array( __CLASS__, 'maybe_remove_php74_required_notice' ) );
|
||||
self::add_action( 'admin_init', array( __CLASS__, 'maybe_remove_legacy_api_removal_notice' ), 20 );
|
||||
|
||||
// @TODO: This prevents Action Scheduler async jobs from storing empty list of notices during WC installation.
|
||||
// That could lead to OBW not starting and 'Run setup wizard' notice not appearing in WP admin, which we want
|
||||
@@ -120,48 +120,77 @@ class WC_Admin_Notices {
|
||||
self::add_notice( 'template_files' );
|
||||
self::add_min_version_notice();
|
||||
self::add_maxmind_missing_license_key_notice();
|
||||
self::maybe_add_php74_required_notice();
|
||||
self::maybe_add_legacy_api_removal_notice();
|
||||
}
|
||||
|
||||
// phpcs:disable Generic.Commenting.Todo.TaskFound
|
||||
|
||||
/**
|
||||
* Add an admin notice about the bump of the required PHP version in WooCommerce 8.2
|
||||
* if the current PHP version is too old.
|
||||
* Add an admin notice about the removal of the Legacy REST API if the said API is enabled,
|
||||
* and a notice about soon to be unsupported webhooks with Legacy API payload if at least one of these exist.
|
||||
*
|
||||
* TODO: Remove this method in WooCommerce 8.2.
|
||||
* TODO: Change this method in WooCommerce 9.0 so that it checks if the Legacy REST API extension is installed, and if not, it points to the extension URL in the WordPress plugins directory.
|
||||
*/
|
||||
private static function maybe_add_php74_required_notice() {
|
||||
if ( version_compare( phpversion(), '7.4', '>=' ) ) {
|
||||
private static function maybe_add_legacy_api_removal_notice() {
|
||||
if ( is_plugin_active( 'woocommerce-legacy-rest-api/woocommerce-legacy-rest-api.php' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
self::add_custom_notice(
|
||||
'php74_required_in_woo_82',
|
||||
sprintf(
|
||||
'%s%s',
|
||||
if ( 'yes' === get_option( 'woocommerce_api_enabled' ) ) {
|
||||
self::add_custom_notice(
|
||||
'legacy_api_removed_in_woo_90',
|
||||
sprintf(
|
||||
'<h4>%s</h4>',
|
||||
esc_html__( 'PHP version requirements will change soon', 'woocommerce' )
|
||||
),
|
||||
sprintf(
|
||||
// translators: Placeholder is a URL.
|
||||
wpautop( wp_kses_data( __( 'WooCommerce 8.2, scheduled for <b>October 2023</b>, will require PHP 7.4 or newer to work. Your server is currently running an older version of PHP, so this change will impact your store. Upgrading to at least PHP 8.0 is recommended. <b><a href="%s">Learn more about this change.</a></b>', 'woocommerce' ) ) ),
|
||||
'https://developer.woocommerce.com/2023/06/05/new-requirement-for-woocommerce-8-2-php-7-4/'
|
||||
'%s%s',
|
||||
sprintf(
|
||||
'<h4>%s</h4>',
|
||||
esc_html__( 'The WooCommerce Legacy REST API will be removed soon', 'woocommerce' )
|
||||
),
|
||||
sprintf(
|
||||
// translators: Placeholders are URLs.
|
||||
wpautop( wp_kses_data( __( 'The WooCommerce Legacy REST API, <a href="%1$s">currently enabled in this site</a>, will be removed in WooCommerce 9.0. A separate WooCommerce extension will be available to keep it enabled. <b><a target=”_blank” href="%2$s">Learn more about this change.</a></b>', 'woocommerce' ) ) ),
|
||||
admin_url( 'admin.php?page=wc-settings&tab=advanced§ion=legacy_api' ),
|
||||
'https://developer.woocommerce.com/2023/10/03/the-legacy-rest-api-will-move-to-a-dedicated-extension-in-woocommerce-9-0/'
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
);
|
||||
}
|
||||
|
||||
if ( wc_get_container()->get( WebhookUtil::class )->get_legacy_webhooks_count() > 0 ) {
|
||||
self::add_custom_notice(
|
||||
'legacy_webhooks_unsupported_in_woo_90',
|
||||
sprintf(
|
||||
'%s%s',
|
||||
sprintf(
|
||||
'<h4>%s</h4>',
|
||||
esc_html__( 'WooCommerce webhooks that use the Legacy REST API will be unsupported soon', 'woocommerce' )
|
||||
),
|
||||
sprintf(
|
||||
// translators: Placeholders are URLs.
|
||||
wpautop( wp_kses_data( __( 'The WooCommerce Legacy REST API will be removed in WooCommerce 9.0, and this will cause <a href="%1$s">webhooks on this site that are configured to use the Legacy REST API</a> to stop working. A separate WooCommerce extension will be available to allow these webhooks to keep using the Legacy REST API without interruption. You can also edit these webhooks to use the current REST API version to generate the payload instead. <b><a target=”_blank” href="%2$s">Learn more about this change.</a></b>', 'woocommerce' ) ) ),
|
||||
admin_url( 'admin.php?page=wc-settings&tab=advanced§ion=webhooks&legacy=true' ),
|
||||
'https://developer.woocommerce.com/2023/10/03/the-legacy-rest-api-will-move-to-a-dedicated-extension-in-woocommerce-9-0/'
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the admin notice about the bump of the required PHP version in WooCommerce 8.2
|
||||
* if the current PHP version is good.
|
||||
* Remove the admin notice about the removal of the Legacy REST API if the said API is disabled
|
||||
* or if the Legacy REST API extension is installed, and remove the notice about Legacy webhooks
|
||||
* if no such webhooks exist anymore or if the Legacy REST API extension is installed.
|
||||
*
|
||||
* TODO: Remove this method in WooCommerce 8.2.
|
||||
* TODO: Change this method in WooCommerce 9.0 so that the notice gets removed if the Legacy REST API extension is installed and active.
|
||||
*/
|
||||
private static function maybe_remove_php74_required_notice() {
|
||||
if ( version_compare( phpversion(), '7.4', '>=' ) && self::has_notice( 'php74_required_in_woo_82' ) ) {
|
||||
self::remove_notice( 'php74_required_in_woo_82' );
|
||||
private static function maybe_remove_legacy_api_removal_notice() {
|
||||
$plugin_is_active = is_plugin_active( 'woocommerce-legacy-rest-api/woocommerce-legacy-rest-api.php' );
|
||||
|
||||
if ( self::has_notice( 'legacy_api_removed_in_woo_90' ) && ( $plugin_is_active || 'yes' !== get_option( 'woocommerce_api_enabled' ) ) ) {
|
||||
self::remove_notice( 'legacy_api_removed_in_woo_90' );
|
||||
}
|
||||
|
||||
if ( self::has_notice( 'legacy_webhooks_unsupported_in_woo_90' ) && ( $plugin_is_active || 0 === wc_get_container()->get( WebhookUtil::class )->get_legacy_webhooks_count() ) ) {
|
||||
self::remove_notice( 'legacy_webhooks_unsupported_in_woo_90' );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -475,45 +504,12 @@ class WC_Admin_Notices {
|
||||
/**
|
||||
* Notice about WordPress and PHP minimum requirements.
|
||||
*
|
||||
* @deprecated 8.2.0 WordPress and PHP minimum requirements notices are no longer shown.
|
||||
*
|
||||
* @since 3.6.5
|
||||
* @return void
|
||||
*/
|
||||
public static function wp_php_min_requirements_notice() {
|
||||
if ( apply_filters( 'woocommerce_hide_php_wp_nag', get_user_meta( get_current_user_id(), 'dismissed_' . WC_PHP_MIN_REQUIREMENTS_NOTICE . '_notice', true ) ) ) {
|
||||
self::remove_notice( WC_PHP_MIN_REQUIREMENTS_NOTICE );
|
||||
return;
|
||||
}
|
||||
|
||||
$old_php = version_compare( phpversion(), WC_NOTICE_MIN_PHP_VERSION, '<' );
|
||||
$old_wp = version_compare( get_bloginfo( 'version' ), WC_NOTICE_MIN_WP_VERSION, '<' );
|
||||
|
||||
// Both PHP and WordPress up to date version => no notice.
|
||||
if ( ! $old_php && ! $old_wp ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $old_php && $old_wp ) {
|
||||
$msg = sprintf(
|
||||
/* translators: 1: Minimum PHP version 2: Minimum WordPress version */
|
||||
__( 'Update required: WooCommerce will soon require PHP version %1$s and WordPress version %2$s or newer.', 'woocommerce' ),
|
||||
WC_NOTICE_MIN_PHP_VERSION,
|
||||
WC_NOTICE_MIN_WP_VERSION
|
||||
);
|
||||
} elseif ( $old_php ) {
|
||||
$msg = sprintf(
|
||||
/* translators: %s: Minimum PHP version */
|
||||
__( 'Update required: WooCommerce will soon require PHP version %s or newer.', 'woocommerce' ),
|
||||
WC_NOTICE_MIN_PHP_VERSION
|
||||
);
|
||||
} elseif ( $old_wp ) {
|
||||
$msg = sprintf(
|
||||
/* translators: %s: Minimum WordPress version */
|
||||
__( 'Update required: WooCommerce will soon require WordPress version %s or newer.', 'woocommerce' ),
|
||||
WC_NOTICE_MIN_WP_VERSION
|
||||
);
|
||||
}
|
||||
|
||||
include dirname( __FILE__ ) . '/views/html-notice-wp-php-minimum-requirements.php';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -200,7 +200,7 @@ class WC_Admin_Post_Types {
|
||||
9 => sprintf(
|
||||
/* translators: %s: date */
|
||||
__( 'Order scheduled for: %s.', 'woocommerce' ),
|
||||
'<strong>' . date_i18n( __( 'M j, Y @ G:i', 'woocommerce' ), strtotime( $theorder->get_date_created() ) ) . '</strong>'
|
||||
'<strong>' . date_i18n( __( 'M j, Y @ G:i', 'woocommerce' ), strtotime( $theorder->get_date_created() ?? $post->post_date ) ) . '</strong>'
|
||||
),
|
||||
10 => __( 'Order draft updated.', 'woocommerce' ),
|
||||
11 => __( 'Order updated and sent.', 'woocommerce' ),
|
||||
|
||||
@@ -240,6 +240,12 @@ if ( ! class_exists( 'WC_Admin_Settings', false ) ) :
|
||||
if ( ! isset( $value['placeholder'] ) ) {
|
||||
$value['placeholder'] = '';
|
||||
}
|
||||
if ( ! isset( $value['row_class'] ) ) {
|
||||
$value['row_class'] = '';
|
||||
}
|
||||
if ( ! empty( $value['row_class'] ) && substr( $value['row_class'], 0, 16 ) !== 'wc-settings-row-' ) {
|
||||
$value['row_class'] = 'wc-settings-row-' . $value['row_class'];
|
||||
}
|
||||
if ( ! isset( $value['suffix'] ) ) {
|
||||
$value['suffix'] = '';
|
||||
}
|
||||
@@ -281,7 +287,9 @@ if ( ! class_exists( 'WC_Admin_Settings', false ) ) :
|
||||
break;
|
||||
|
||||
case 'info':
|
||||
echo '<tr><th scope="row" class="titledesc"/><td style="' . esc_attr( $value['css'] ) . '">';
|
||||
?><tr valign="top"<?php echo $value['row_class'] ? ' class="' . esc_attr( $value['row_class'] ) . '"' : '' ?>">
|
||||
<th scope="row" class="titledesc"/><td style="<?php echo esc_attr( $value['css'] ); ?>">;
|
||||
<?php
|
||||
echo wp_kses_post( wpautop( wptexturize( $value['text'] ) ) );
|
||||
echo '</td></tr>';
|
||||
break;
|
||||
@@ -312,7 +320,7 @@ if ( ! class_exists( 'WC_Admin_Settings', false ) ) :
|
||||
case 'tel':
|
||||
$option_value = $value['value'];
|
||||
|
||||
?><tr valign="top">
|
||||
?><tr valign="top"<?php echo $value['row_class'] ? ' class="' . esc_attr( $value['row_class'] ) . '"' : '' ?>">
|
||||
<th scope="row" class="titledesc">
|
||||
<label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?> <?php echo $tooltip_html; // WPCS: XSS ok. ?></label>
|
||||
</th>
|
||||
@@ -337,7 +345,7 @@ if ( ! class_exists( 'WC_Admin_Settings', false ) ) :
|
||||
$option_value = $value['value'];
|
||||
|
||||
?>
|
||||
<tr valign="top">
|
||||
<tr valign="top"<?php echo $value['row_class'] ? ' class="' . esc_attr( $value['row_class'] ) . '"' : '' ?>">
|
||||
<th scope="row" class="titledesc">
|
||||
<label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?> <?php echo $tooltip_html; // WPCS: XSS ok. ?></label>
|
||||
</th>
|
||||
@@ -365,7 +373,7 @@ if ( ! class_exists( 'WC_Admin_Settings', false ) ) :
|
||||
$option_value = $value['value'];
|
||||
|
||||
?>
|
||||
<tr valign="top">
|
||||
<tr valign="top"<?php echo $value['row_class'] ? ' class="' . esc_attr( $value['row_class'] ) . '"' : '' ?>">
|
||||
<th scope="row" class="titledesc">
|
||||
<label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?> <?php echo $tooltip_html; // WPCS: XSS ok. ?></label>
|
||||
</th>
|
||||
@@ -391,7 +399,7 @@ if ( ! class_exists( 'WC_Admin_Settings', false ) ) :
|
||||
$option_value = $value['value'];
|
||||
|
||||
?>
|
||||
<tr valign="top">
|
||||
<tr valign="top"<?php echo $value['row_class'] ? ' class="' . esc_attr( $value['row_class'] ) . '"' : '' ?>">
|
||||
<th scope="row" class="titledesc">
|
||||
<label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?> <?php echo $tooltip_html; // WPCS: XSS ok. ?></label>
|
||||
</th>
|
||||
@@ -434,7 +442,7 @@ if ( ! class_exists( 'WC_Admin_Settings', false ) ) :
|
||||
$show_desc_at_end = $value['desc_at_end'] ?? false;
|
||||
|
||||
?>
|
||||
<tr valign="top">
|
||||
<tr valign="top"<?php echo $value['row_class'] ? ' class="' . esc_attr( $value['row_class'] ) . '"' : '' ?>">
|
||||
<th scope="row" class="titledesc">
|
||||
<label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?> <?php echo $tooltip_html; // WPCS: XSS ok. ?></label>
|
||||
</th>
|
||||
@@ -494,6 +502,9 @@ if ( ! class_exists( 'WC_Admin_Settings', false ) ) :
|
||||
if ( 'option' === $value['show_if_checked'] ) {
|
||||
$visibility_class[] = 'show_options_if_checked';
|
||||
}
|
||||
if ( $value['row_class'] ) {
|
||||
$visibility_class[] = $value['row_class'];
|
||||
}
|
||||
|
||||
$must_disable = $value['disabled'] ?? false;
|
||||
|
||||
@@ -566,7 +577,7 @@ if ( ! class_exists( 'WC_Admin_Settings', false ) ) :
|
||||
}
|
||||
|
||||
?>
|
||||
<tr valign="top">
|
||||
<tr valign="top"<?php echo $value['row_class'] ? ' class="' . esc_attr( $value['row_class'] ) . '"' : '' ?>">
|
||||
<th scope="row" class="titledesc">
|
||||
<label><?php echo esc_html( $value['title'] ); ?> <?php echo $tooltip_html . $disabled_message; // WPCS: XSS ok. ?></label>
|
||||
</th>
|
||||
@@ -600,7 +611,7 @@ if ( ! class_exists( 'WC_Admin_Settings', false ) ) :
|
||||
}
|
||||
|
||||
?>
|
||||
<tr valign="top" class="single_select_page">
|
||||
<tr valign="top" class="single_select_page"<?php echo $value['row_class'] ? ' class="' . esc_attr( $value['row_class'] ) . '"' : '' ?>">
|
||||
<th scope="row" class="titledesc">
|
||||
<label><?php echo esc_html( $value['title'] ); ?> <?php echo $tooltip_html; // WPCS: XSS ok. ?></label>
|
||||
</th>
|
||||
@@ -625,7 +636,7 @@ if ( ! class_exists( 'WC_Admin_Settings', false ) ) :
|
||||
);
|
||||
}
|
||||
?>
|
||||
<tr valign="top" class="single_select_page">
|
||||
<tr valign="top" class="single_select_page"<?php echo $value['row_class'] ? ' class="' . esc_attr( $value['row_class'] ) . '"' : '' ?>">
|
||||
<th scope="row" class="titledesc">
|
||||
<label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?> <?php echo $tooltip_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></label>
|
||||
</th>
|
||||
@@ -665,7 +676,7 @@ if ( ! class_exists( 'WC_Admin_Settings', false ) ) :
|
||||
$state = '*';
|
||||
}
|
||||
?>
|
||||
<tr valign="top">
|
||||
<tr valign="top"<?php echo $value['row_class'] ? ' class="' . esc_attr( $value['row_class'] ) . '"' : '' ?>">
|
||||
<th scope="row" class="titledesc">
|
||||
<label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?> <?php echo $tooltip_html; // WPCS: XSS ok. ?></label>
|
||||
</th>
|
||||
@@ -689,7 +700,7 @@ if ( ! class_exists( 'WC_Admin_Settings', false ) ) :
|
||||
|
||||
asort( $countries );
|
||||
?>
|
||||
<tr valign="top">
|
||||
<tr valign="top"<?php echo $value['row_class'] ? ' class="' . esc_attr( $value['row_class'] ) . '"' : '' ?>">
|
||||
<th scope="row" class="titledesc">
|
||||
<label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?> <?php echo $tooltip_html; // WPCS: XSS ok. ?></label>
|
||||
</th>
|
||||
@@ -718,7 +729,7 @@ if ( ! class_exists( 'WC_Admin_Settings', false ) ) :
|
||||
);
|
||||
$option_value = wc_parse_relative_date_option( $value['value'] );
|
||||
?>
|
||||
<tr valign="top">
|
||||
<tr valign="top"<?php echo $value['row_class'] ? ' class="' . esc_attr( $value['row_class'] ) . '"' : '' ?>">
|
||||
<th scope="row" class="titledesc">
|
||||
<label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?> <?php echo $tooltip_html; // WPCS: XSS ok. ?></label>
|
||||
</th>
|
||||
|
||||
+34
-7
@@ -6,6 +6,8 @@
|
||||
* @version 3.3.0
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\Internal\Utilities\WebhookUtil;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
if ( ! class_exists( 'WP_List_Table' ) ) {
|
||||
@@ -174,7 +176,8 @@ class WC_Admin_Webhooks_Table_List extends WP_List_Table {
|
||||
$num_webhooks = $data_store->get_count_webhooks_by_status();
|
||||
$total_webhooks = array_sum( (array) $num_webhooks );
|
||||
$statuses = array_keys( wc_get_webhook_statuses() );
|
||||
$class = empty( $_REQUEST['status'] ) ? ' class="current"' : ''; // WPCS: input var okay. CSRF ok.
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
$class = empty( $_REQUEST['status'] ) && empty( $_REQUEST['legacy'] ) ? ' class="current"' : '';
|
||||
|
||||
/* translators: %s: count */
|
||||
$status_links['all'] = "<a href='admin.php?page=wc-settings&tab=advanced&section=webhooks'$class>" . sprintf( _nx( 'All <span class="count">(%s)</span>', 'All <span class="count">(%s)</span>', $total_webhooks, 'posts', 'woocommerce' ), number_format_i18n( $total_webhooks ) ) . '</a>';
|
||||
@@ -186,7 +189,8 @@ class WC_Admin_Webhooks_Table_List extends WP_List_Table {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( isset( $_REQUEST['status'] ) && sanitize_key( wp_unslash( $_REQUEST['status'] ) ) === $status_name ) { // WPCS: input var okay, CSRF ok.
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
if ( isset( $_REQUEST['status'] ) && sanitize_key( wp_unslash( $_REQUEST['status'] ) ) === $status_name ) {
|
||||
$class = ' class="current"';
|
||||
}
|
||||
|
||||
@@ -195,6 +199,20 @@ class WC_Admin_Webhooks_Table_List extends WP_List_Table {
|
||||
$status_links[ $status_name ] = "<a href='admin.php?page=wc-settings&tab=advanced&section=webhooks&status=$status_name'$class>" . sprintf( translate_nooped_plural( $label, $num_webhooks[ $status_name ] ), number_format_i18n( $num_webhooks[ $status_name ] ) ) . '</a>';
|
||||
}
|
||||
|
||||
$legacy_webhooks_count = wc_get_container()->get( WebhookUtil::class )->get_legacy_webhooks_count();
|
||||
if ( $legacy_webhooks_count > 0 ) {
|
||||
$class = '';
|
||||
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
if ( 'true' === sanitize_key( wp_unslash( $_REQUEST['legacy'] ?? '' ) ) ) {
|
||||
$class = ' class="current"';
|
||||
}
|
||||
|
||||
$label = $this->get_status_label( __( 'Legacy', 'woocommerce' ), $legacy_webhooks_count );
|
||||
|
||||
$status_links['legacy'] = "<a href='admin.php?page=wc-settings&tab=advanced&section=webhooks&legacy=true'$class>" . sprintf( translate_nooped_plural( $label, $legacy_webhooks_count ), number_format_i18n( $legacy_webhooks_count ) ) . '</a>';
|
||||
}
|
||||
|
||||
return $status_links;
|
||||
}
|
||||
|
||||
@@ -216,12 +234,16 @@ class WC_Admin_Webhooks_Table_List extends WP_List_Table {
|
||||
$action = $this->current_action();
|
||||
$webhooks = isset( $_REQUEST['webhook'] ) ? array_map( 'absint', (array) $_REQUEST['webhook'] ) : array(); // WPCS: input var okay, CSRF ok.
|
||||
|
||||
if ( ! current_user_can( 'manage_woocommerce' ) ) {
|
||||
wp_die( esc_html__( 'You do not have permission to edit Webhooks', 'woocommerce' ) );
|
||||
}
|
||||
if ( false !== $action ) {
|
||||
check_admin_referer( 'woocommerce-settings' );
|
||||
|
||||
if ( 'delete' === $action ) {
|
||||
WC_Admin_Webhooks::bulk_delete( $webhooks );
|
||||
if ( ! current_user_can( 'manage_woocommerce' ) ) {
|
||||
wp_die( esc_html__( 'You do not have permission to edit Webhooks', 'woocommerce' ) );
|
||||
}
|
||||
|
||||
if ( 'delete' === $action ) {
|
||||
WC_Admin_Webhooks::bulk_delete( $webhooks );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,6 +321,11 @@ class WC_Admin_Webhooks_Table_List extends WP_List_Table {
|
||||
|
||||
$args['paginate'] = true;
|
||||
|
||||
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
if ( 'true' === sanitize_key( wp_unslash( $_REQUEST['legacy'] ?? null ) ) ) {
|
||||
$args['api_version'] = -1;
|
||||
}
|
||||
|
||||
// Get the webhooks.
|
||||
$data_store = WC_Data_Store::load( 'webhook' );
|
||||
$webhooks = $data_store->search_webhooks( $args );
|
||||
|
||||
@@ -295,7 +295,7 @@ class WC_Admin_Webhooks {
|
||||
private static function table_list_output() {
|
||||
global $webhooks_table_list;
|
||||
|
||||
echo '<h2 class="wc-table-list-header">' . esc_html__( 'Webhooks', 'woocommerce' ) . ' <a href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=advanced§ion=webhooks&edit-webhook=0' ) ) . '" class="add-new-h2">' . esc_html__( 'Add webhook', 'woocommerce' ) . '</a></h2>';
|
||||
echo '<h2 class="wc-table-list-header">' . esc_html__( 'Webhooks', 'woocommerce' ) . ' <a href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=advanced§ion=webhooks&edit-webhook=0' ) ) . '" class="page-title-action">' . esc_html__( 'Add webhook', 'woocommerce' ) . '</a></h2>';
|
||||
|
||||
// Get the webhooks count.
|
||||
$data_store = WC_Data_Store::load( 'webhook' );
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
/**
|
||||
* WooCommerce Admin Helper - React admin interface
|
||||
*
|
||||
* @package WooCommerce\Admin\Helper
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* WC_Helper Class
|
||||
*
|
||||
* The main entry-point for all things related to the Helper.
|
||||
* The Helper manages the connection between the store and
|
||||
* an account on WooCommerce.com.
|
||||
*/
|
||||
class WC_Helper_Admin {
|
||||
|
||||
/**
|
||||
* Loads the class, runs on init
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public static function load() {
|
||||
add_filter( 'woocommerce_admin_shared_settings', array( __CLASS__, 'add_marketplace_settings' ) );
|
||||
add_filter( 'rest_api_init', array( __CLASS__, 'register_rest_routes' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes settings onto the WooCommerce Admin global settings object (wcSettings).
|
||||
*
|
||||
* @param mixed $settings The settings object we're amending.
|
||||
*
|
||||
* @return mixed $settings
|
||||
*/
|
||||
public static function add_marketplace_settings( $settings ) {
|
||||
$auth_user_data = WC_Helper_Options::get( 'auth_user_data', array() );
|
||||
$auth_user_email = isset( $auth_user_data['email'] ) ? $auth_user_data['email'] : '';
|
||||
|
||||
$settings['wccomHelper'] = array(
|
||||
'isConnected' => WC_Helper::is_site_connected(),
|
||||
'connectURL' => self::get_connection_url(),
|
||||
'userEmail' => $auth_user_email,
|
||||
'userAvatar' => get_avatar_url( $auth_user_email, array( 'size' => '48' ) ),
|
||||
'storeCountry' => wc_get_base_location()['country'],
|
||||
'inAppPurchaseURLParams' => WC_Admin_Addons::get_in_app_purchase_url_params(),
|
||||
);
|
||||
|
||||
return $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the URL for connecting or disconnecting the store to/from WooCommerce.com.
|
||||
* Approach taken from existing helper code that isn't exposed.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function get_connection_url() {
|
||||
// No active connection.
|
||||
if ( ! WC_Helper::is_site_connected() ) {
|
||||
$connect_url = add_query_arg(
|
||||
array(
|
||||
'page' => 'wc-addons',
|
||||
'section' => 'helper',
|
||||
'wc-helper-connect' => 1,
|
||||
'wc-helper-nonce' => wp_create_nonce( 'connect' ),
|
||||
),
|
||||
admin_url( 'admin.php' )
|
||||
);
|
||||
|
||||
return $connect_url;
|
||||
}
|
||||
|
||||
$connect_url = add_query_arg(
|
||||
array(
|
||||
'page' => 'wc-addons',
|
||||
'section' => 'helper',
|
||||
'wc-helper-disconnect' => 1,
|
||||
'wc-helper-nonce' => wp_create_nonce( 'disconnect' ),
|
||||
),
|
||||
admin_url( 'admin.php' )
|
||||
);
|
||||
|
||||
return $connect_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the REST routes for the featured products endpoint.
|
||||
* This endpoint is used by the WooCommerce > Extensions > Discover
|
||||
* page.
|
||||
*/
|
||||
public static function register_rest_routes() {
|
||||
register_rest_route(
|
||||
'wc/v3',
|
||||
'/marketplace/featured',
|
||||
array(
|
||||
'methods' => 'GET',
|
||||
'callback' => array( __CLASS__, 'get_featured' ),
|
||||
'permission_callback' => array( __CLASS__, 'get_permission' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Extensions page can only be accessed by users with the manage_woocommerce
|
||||
* capability. So the API mimics that behavior.
|
||||
*/
|
||||
public static function get_permission() {
|
||||
return current_user_can( 'manage_woocommerce' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch featured procucts from WooCommerce.com and serve them
|
||||
* as JSON.
|
||||
*/
|
||||
public static function get_featured() {
|
||||
$featured = WC_Admin_Addons::fetch_featured();
|
||||
|
||||
if ( is_wp_error( $featured ) ) {
|
||||
wp_send_json_error( array( 'message' => $featured->get_error_message() ) );
|
||||
}
|
||||
|
||||
wp_send_json( $featured );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
WC_Helper_Admin::load();
|
||||
+12
-8
@@ -68,17 +68,21 @@ class WC_Helper_Updater {
|
||||
$item['package'] = 'woocommerce-com-expired-' . $plugin['_product_id'];
|
||||
}
|
||||
|
||||
if ( version_compare( $plugin['Version'], $data['version'], '<' ) ) {
|
||||
$transient->response[ $filename ] = (object) $item;
|
||||
unset( $transient->no_update[ $filename ] );
|
||||
} else {
|
||||
$transient->no_update[ $filename ] = (object) $item;
|
||||
unset( $transient->response[ $filename ] );
|
||||
if ( $transient instanceof stdClass ) {
|
||||
if ( version_compare( $plugin['Version'], $data['version'], '<' ) ) {
|
||||
$transient->response[ $filename ] = (object) $item;
|
||||
unset( $transient->no_update[ $filename ] );
|
||||
} else {
|
||||
$transient->no_update[ $filename ] = (object) $item;
|
||||
unset( $transient->response[ $filename ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$translations = self::get_translations_update_data();
|
||||
$transient->translations = array_merge( isset( $transient->translations ) ? $transient->translations : array(), $translations );
|
||||
if ( $transient instanceof stdClass ) {
|
||||
$translations = self::get_translations_update_data();
|
||||
$transient->translations = array_merge( isset( $transient->translations ) ? $transient->translations : array(), $translations );
|
||||
}
|
||||
|
||||
return $transient;
|
||||
}
|
||||
|
||||
@@ -58,6 +58,7 @@ class WC_Helper {
|
||||
include_once dirname( __FILE__ ) . '/class-wc-helper-updater.php';
|
||||
include_once dirname( __FILE__ ) . '/class-wc-helper-plugin-info.php';
|
||||
include_once dirname( __FILE__ ) . '/class-wc-helper-compat.php';
|
||||
include_once dirname( __FILE__ ) . '/class-wc-helper-admin.php';
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1198,6 +1199,11 @@ class WC_Helper {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Omit the WooCommerce plugin used on Woo Express sites.
|
||||
if ( 'WooCommerce' === $data['Name'] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$data['_filename'] = $filename;
|
||||
$data['_product_id'] = absint( $product_id );
|
||||
$data['_file_id'] = $file_id;
|
||||
|
||||
@@ -60,7 +60,8 @@
|
||||
$class_html = $current_filter === $key ? 'class="current"' : '';
|
||||
?>
|
||||
<li>
|
||||
<a <?php echo esc_html( $class_html ); ?> href="<?php echo esc_url( $url ); ?>">
|
||||
<?php // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||
<a <?php echo $class_html; ?> href="<?php echo esc_url( $url ); ?>">
|
||||
<?php echo esc_html( $label ); ?>
|
||||
<span class="count">(<?php echo absint( $counts[ $key ] ); ?>)</span>
|
||||
</a>
|
||||
|
||||
@@ -7,10 +7,17 @@
|
||||
* @deprecated 5.7.0
|
||||
*/
|
||||
|
||||
use Automattic\WooCommerce\Utilities\FeaturesUtil;
|
||||
|
||||
$addons_url = admin_url( 'admin.php?page=wc-addons' );
|
||||
if ( FeaturesUtil::feature_is_enabled( 'marketplace' ) ) {
|
||||
$addons_url = admin_url( 'admin.php?page=wc-admin&path=/extensions&tab=extensions' );
|
||||
}
|
||||
|
||||
defined( 'ABSPATH' ) || exit(); ?>
|
||||
|
||||
<nav class="nav-tab-wrapper woo-nav-tab-wrapper">
|
||||
<a href="<?php echo esc_url( admin_url( 'admin.php?page=wc-addons' ) ); ?>" class="nav-tab"><?php esc_html_e( 'Browse Extensions', 'woocommerce' ); ?></a>
|
||||
<a href="<?php echo esc_url( $addons_url ); ?>" class="nav-tab"><?php esc_html_e( 'Browse Extensions', 'woocommerce' ); ?></a>
|
||||
|
||||
<?php
|
||||
$count_html = WC_Helper_Updater::get_updates_count_html();
|
||||
|
||||
+1
-1
@@ -103,7 +103,7 @@ class WC_Meta_Box_Order_Actions {
|
||||
$trash_order_url = add_query_arg(
|
||||
array(
|
||||
'action' => 'trash',
|
||||
'order' => array( $order_id ),
|
||||
'id' => array( $order_id ),
|
||||
'_wp_http_referer' => $order_list_url,
|
||||
),
|
||||
$order_list_url
|
||||
|
||||
+2
-2
@@ -41,7 +41,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
<select multiple="multiple"
|
||||
data-minimum_input_length="0"
|
||||
data-limit="50" data-return_id="id"
|
||||
data-placeholder="<?php esc_attr_e( 'Select terms', 'woocommerce' ); ?>"
|
||||
data-placeholder="<?php esc_attr_e( 'Select values', 'woocommerce' ); ?>"
|
||||
data-orderby="<?php echo esc_attr( $attribute_orderby ); ?>"
|
||||
class="multiselect attribute_values wc-taxonomy-term-search"
|
||||
name="attribute_values[<?php echo esc_attr( $i ); ?>][]"
|
||||
@@ -79,7 +79,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
do_action( 'woocommerce_product_option_terms', $attribute_taxonomy, $i, $attribute );
|
||||
} else {
|
||||
?>
|
||||
<textarea name="attribute_values[<?php echo esc_attr( $i ); ?>]" cols="5" rows="5" placeholder="<?php /* translators: %s: WC_DELIMITER */ printf( esc_attr__( 'Enter options for customers to choose from, f.e. “Blue” or “Large”. Use “%s” to separate different options.', 'woocommerce' ), esc_attr( WC_DELIMITER ) ); ?>"><?php echo esc_textarea( wc_implode_text_attributes( $attribute->get_options() ) ); ?></textarea>
|
||||
<textarea name="attribute_values[<?php echo esc_attr( $i ); ?>]" cols="5" rows="5"><?php echo esc_textarea( wc_implode_text_attributes( $attribute->get_options() ) ); ?></textarea>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
|
||||
+3
-2
@@ -17,14 +17,15 @@ $product_attributes = $product_object->get_attributes( 'edit' );
|
||||
?>
|
||||
<div id="product_attributes" class="panel wc-metaboxes-wrapper hidden">
|
||||
<div class="toolbar toolbar-top">
|
||||
<div id="message" class="inline notice woocommerce-message">
|
||||
<p>
|
||||
<div id="message" class="inline notice woocommerce-message is-dismissible">
|
||||
<p class="help">
|
||||
<?php
|
||||
esc_html_e(
|
||||
'Add descriptive pieces of information that customers can use to search for this product on your store, such as “Material” or “Brand”.',
|
||||
'woocommerce'
|
||||
);
|
||||
?>
|
||||
<button type="button" class="notice-dismiss"><span class="screen-reader-text"><?php esc_html_e( 'Dismiss this notice.', 'woocommerce' ); ?></span></button>
|
||||
</p>
|
||||
</div>
|
||||
<span class="expand-close">
|
||||
|
||||
+11
-7
@@ -10,13 +10,10 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
}
|
||||
?>
|
||||
<div id="inventory_product_data" class="panel woocommerce_options_panel hidden">
|
||||
<div class="inline notice woocommerce-message show_if_variable">
|
||||
<p>
|
||||
<?php echo esc_html_e( 'Settings below apply to all variations without manual stock management enabled.', 'woocommerce' ); ?> <a target="_blank" href="https://woocommerce.com/document/variable-product/"><?php esc_html_e( 'Learn more', 'woocommerce' ); ?></a>
|
||||
</p>
|
||||
</div>
|
||||
<div class="options_group">
|
||||
<?php
|
||||
$info_img_url = WC_ADMIN_IMAGES_FOLDER_URL . '/icons/info.svg';
|
||||
|
||||
if ( wc_product_sku_enabled() ) {
|
||||
woocommerce_wp_text_input(
|
||||
array(
|
||||
@@ -31,6 +28,15 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
|
||||
do_action( 'woocommerce_product_options_sku' );
|
||||
|
||||
?>
|
||||
<div class="inline notice woocommerce-message show_if_variable">
|
||||
<img class="info-icon" src="<?php echo esc_url( $info_img_url ); ?>" />
|
||||
<p>
|
||||
<?php echo esc_html_e( 'Settings below apply to all variations without manual stock management enabled. ', 'woocommerce' ); ?> <a target="_blank" href="https://woocommerce.com/document/variable-product/"><?php esc_html_e( 'Learn more', 'woocommerce' ); ?></a>
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
if ( 'yes' === get_option( 'woocommerce_manage_stock' ) ) {
|
||||
|
||||
woocommerce_wp_checkbox(
|
||||
@@ -69,8 +75,6 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
'value' => $product_object->get_backorders( 'edit' ),
|
||||
'label' => __( 'Allow backorders?', 'woocommerce' ),
|
||||
'options' => wc_get_product_backorder_options(),
|
||||
'desc_tip' => true,
|
||||
'description' => __( 'If managing stock, this controls whether or not backorders are allowed. If enabled, stock quantity can go below 0.', 'woocommerce' ),
|
||||
);
|
||||
|
||||
/**
|
||||
|
||||
+22
-9
@@ -63,7 +63,7 @@ class WC_Settings_Advanced extends WC_Settings_Page {
|
||||
array(
|
||||
'title' => __( 'Cart page', 'woocommerce' ),
|
||||
/* Translators: %s Page contents. */
|
||||
'desc' => sprintf( __( 'Page contents: [%s]', 'woocommerce' ), apply_filters( 'woocommerce_cart_shortcode_tag', 'woocommerce_cart' ) ),
|
||||
'desc' => __( 'Page where shoppers review their shopping cart', 'woocommerce' ),
|
||||
'id' => 'woocommerce_cart_page_id',
|
||||
'type' => 'single_select_page_with_search',
|
||||
'default' => '',
|
||||
@@ -83,7 +83,7 @@ class WC_Settings_Advanced extends WC_Settings_Page {
|
||||
array(
|
||||
'title' => __( 'Checkout page', 'woocommerce' ),
|
||||
/* Translators: %s Page contents. */
|
||||
'desc' => sprintf( __( 'Page contents: [%s]', 'woocommerce' ), apply_filters( 'woocommerce_checkout_shortcode_tag', 'woocommerce_checkout' ) ),
|
||||
'desc' => __( 'Page where shoppers go to finalize their purchase', 'woocommerce' ),
|
||||
'id' => 'woocommerce_checkout_page_id',
|
||||
'type' => 'single_select_page_with_search',
|
||||
'default' => wc_get_page_id( 'checkout' ),
|
||||
@@ -383,6 +383,25 @@ class WC_Settings_Advanced extends WC_Settings_Page {
|
||||
* @return array
|
||||
*/
|
||||
protected function get_settings_for_legacy_api_section() {
|
||||
$enable_legacy_api_setting = array(
|
||||
'title' => __( 'Legacy API', 'woocommerce' ),
|
||||
'desc' => __( 'Enable the legacy REST API', 'woocommerce' ),
|
||||
'id' => 'woocommerce_api_enabled',
|
||||
'type' => 'checkbox',
|
||||
'default' => 'no',
|
||||
);
|
||||
|
||||
if ( ! is_plugin_active( 'woocommerce-legacy-rest-api/woocommerce-legacy-rest-api.php' ) ) {
|
||||
$enable_legacy_api_setting['desc_tip'] = sprintf(
|
||||
// translators: Placeholder is a URL.
|
||||
__(
|
||||
'⚠️ <b>️The Legacy REST API will be removed in WooCommerce 9.0.</b> A separate WooCommerce extension will soon be available to keep it enabled. <b><a target=”_blank” href="%s">Learn more about this change.</a></b>',
|
||||
'woocommerce'
|
||||
),
|
||||
'https://developer.woocommerce.com/2023/10/03/the-legacy-rest-api-will-move-to-a-dedicated-extension-in-woocommerce-9-0/'
|
||||
);
|
||||
}
|
||||
|
||||
$settings =
|
||||
array(
|
||||
array(
|
||||
@@ -391,13 +410,7 @@ class WC_Settings_Advanced extends WC_Settings_Page {
|
||||
'desc' => '',
|
||||
'id' => 'legacy_api_options',
|
||||
),
|
||||
array(
|
||||
'title' => __( 'Legacy API', 'woocommerce' ),
|
||||
'desc' => __( 'Enable the legacy REST API', 'woocommerce' ),
|
||||
'id' => 'woocommerce_api_enabled',
|
||||
'type' => 'checkbox',
|
||||
'default' => 'no',
|
||||
),
|
||||
$enable_legacy_api_setting,
|
||||
array(
|
||||
'type' => 'sectionend',
|
||||
'id' => 'legacy_api_options',
|
||||
|
||||
@@ -136,10 +136,9 @@ $current_section_name = __( 'Browse Categories', 'woocommerce' );
|
||||
|
||||
<?php if ( 'Storefront' !== $theme['Name'] && '_featured' !== $current_section ) : ?>
|
||||
<?php
|
||||
$storefront_url = WC_Admin_Addons::add_in_app_purchase_url_params( 'https://woocommerce.com/storefront/?utm_source=extensionsscreen&utm_medium=product&utm_campaign=wcaddon' );
|
||||
$storefront_url = WC_Admin_Addons::add_in_app_purchase_url_params( 'https://woocommerce.com/products/storefront/?utm_source=extensionsscreen&utm_medium=product&utm_campaign=wcaddon' );
|
||||
?>
|
||||
<div class="storefront">
|
||||
<a href="<?php echo esc_url( $storefront_url ); ?>" target="_blank"><img src="<?php echo esc_url( WC()->plugin_url() ); ?>/assets/images/storefront.png" alt="<?php esc_attr_e( 'Storefront', 'woocommerce' ); ?>" /></a>
|
||||
<h2><?php esc_html_e( 'Looking for a WooCommerce theme?', 'woocommerce' ); ?></h2>
|
||||
<p><?php echo wp_kses_post( __( 'We recommend Storefront, the <em>official</em> WooCommerce theme.', 'woocommerce' ) ); ?></p>
|
||||
<p><?php echo wp_kses_post( __( 'Storefront is an intuitive, flexible and <strong>free</strong> WordPress theme offering deep integration with WooCommerce and many of the most popular customer-facing extensions.', 'woocommerce' ) ); ?></p>
|
||||
|
||||
+1
-19
@@ -244,25 +244,7 @@ $untested_plugins = $plugin_updates->get_untested_plugins( WC()->version, Cons
|
||||
<td data-export-label="PHP Version"><?php esc_html_e( 'PHP version', 'woocommerce' ); ?>:</td>
|
||||
<td class="help"><?php echo wc_help_tip( esc_html__( 'The version of PHP installed on your hosting server.', 'woocommerce' ) ); /* phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped */ ?></td>
|
||||
<td>
|
||||
<?php
|
||||
if ( version_compare( $environment['php_version'], '7.2', '>=' ) ) {
|
||||
echo '<mark class="yes">' . esc_html( $environment['php_version'] ) . '</mark>';
|
||||
} else {
|
||||
$update_link = ' <a href="https://docs.woocommerce.com/document/how-to-update-your-php-version/" target="_blank">' . esc_html__( 'How to update your PHP version', 'woocommerce' ) . '</a>';
|
||||
$class = 'error';
|
||||
|
||||
if ( version_compare( $environment['php_version'], '5.4', '<' ) ) {
|
||||
$notice = '<span class="dashicons dashicons-warning"></span> ' . __( 'WooCommerce will run under this version of PHP, however, some features such as geolocation are not compatible. Support for this version will be dropped in the next major release. We recommend using PHP version 7.2 or above for greater performance and security.', 'woocommerce' ) . $update_link;
|
||||
} elseif ( version_compare( $environment['php_version'], '5.6', '<' ) ) {
|
||||
$notice = '<span class="dashicons dashicons-warning"></span> ' . __( 'WooCommerce will run under this version of PHP, however, it has reached end of life. We recommend using PHP version 7.2 or above for greater performance and security.', 'woocommerce' ) . $update_link;
|
||||
} elseif ( version_compare( $environment['php_version'], '7.2', '<' ) ) {
|
||||
$notice = __( 'We recommend using PHP version 7.2 or above for greater performance and security.', 'woocommerce' ) . $update_link;
|
||||
$class = 'recommendation';
|
||||
}
|
||||
|
||||
echo '<mark class="' . esc_attr( $class ) . '">' . esc_html( $environment['php_version'] ) . ' - ' . wp_kses_post( $notice ) . '</mark>';
|
||||
}
|
||||
?>
|
||||
<?php echo '<mark class="yes">' . esc_html( $environment['php_version'] ) . '</mark>'; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if ( function_exists( 'ini_get' ) ) : ?>
|
||||
|
||||
@@ -209,7 +209,7 @@ class WC_AJAX {
|
||||
function( $response, $data ) use ( $ajax_callback ) {
|
||||
return call_user_func_array( array( __CLASS__, $ajax_callback ), func_get_args() );
|
||||
},
|
||||
10,
|
||||
11,
|
||||
2
|
||||
);
|
||||
}
|
||||
@@ -971,6 +971,8 @@ class WC_AJAX {
|
||||
$data['date_created'] = $data['date_created'] ? $data['date_created']->getTimestamp() : null;
|
||||
$data['date_modified'] = $data['date_modified'] ? $data['date_modified']->getTimestamp() : null;
|
||||
|
||||
unset( $data['meta_data'] );
|
||||
|
||||
$customer_data = apply_filters( 'woocommerce_ajax_get_customer_details', $data, $customer, $user_id );
|
||||
wp_send_json( $customer_data );
|
||||
}
|
||||
@@ -3615,7 +3617,7 @@ class WC_AJAX {
|
||||
* @param array $data Data sent through the heartbeat.
|
||||
* @return array Response to be sent.
|
||||
*/
|
||||
private static function order_refresh_lock( $response, $data ) : array {
|
||||
private static function order_refresh_lock( $response, $data ) {
|
||||
return wc_get_container()->get( Automattic\WooCommerce\Internal\Admin\Orders\EditLock::class )->refresh_lock_ajax( $response, $data );
|
||||
}
|
||||
|
||||
@@ -3628,7 +3630,7 @@ class WC_AJAX {
|
||||
* @param array $data Data sent through the heartbeat.
|
||||
* @return array Response to be sent.
|
||||
*/
|
||||
private static function check_locked_orders( $response, $data ) : array {
|
||||
private static function check_locked_orders( $response, $data ) {
|
||||
return wc_get_container()->get( Automattic\WooCommerce\Internal\Admin\Orders\EditLock::class )->check_locked_orders_ajax( $response, $data );
|
||||
}
|
||||
|
||||
|
||||
@@ -26,14 +26,6 @@ final class WC_Cart_Fees {
|
||||
*/
|
||||
private $fees = array();
|
||||
|
||||
/**
|
||||
* Reference to cart object.
|
||||
*
|
||||
* @since 3.2.0
|
||||
* @var WC_Cart
|
||||
*/
|
||||
private $cart;
|
||||
|
||||
/**
|
||||
* New fees are made out of these props.
|
||||
*
|
||||
@@ -51,16 +43,18 @@ final class WC_Cart_Fees {
|
||||
/**
|
||||
* Constructor. Reference to the cart.
|
||||
*
|
||||
* @param null $deprecated Deprecated since WooCommerce 8.2.0.
|
||||
*
|
||||
* @since 3.2.0
|
||||
* @throws Exception If missing WC_Cart object.
|
||||
* @param WC_Cart $cart Cart object.
|
||||
*/
|
||||
public function __construct( &$cart ) {
|
||||
if ( ! is_a( $cart, 'WC_Cart' ) ) {
|
||||
throw new Exception( 'A valid WC_Cart object is required' );
|
||||
public function __construct( $deprecated = null ) {
|
||||
if ( isset( $deprecated ) ) {
|
||||
wc_doing_it_wrong(
|
||||
'new WC_Cart_Fees',
|
||||
'You don\'t need to pass a cart parameter to the WC_Cart_Fees constructor anymore',
|
||||
'8.2.0'
|
||||
);
|
||||
}
|
||||
|
||||
$this->cart = $cart;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,14 +33,24 @@ final class WC_Cart_Session {
|
||||
*
|
||||
* @param WC_Cart $cart Cart object to calculate totals for.
|
||||
*/
|
||||
public function __construct( &$cart ) {
|
||||
public function __construct( $cart ) {
|
||||
if ( ! is_a( $cart, 'WC_Cart' ) ) {
|
||||
throw new Exception( 'A valid WC_Cart object is required' );
|
||||
}
|
||||
|
||||
$this->set_cart( $cart );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cart instance.
|
||||
*
|
||||
* @param WC_Cart $cart Cart object.
|
||||
*/
|
||||
public function set_cart( WC_Cart $cart ) {
|
||||
$this->cart = $cart;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Register methods for this object on the appropriate WordPress hooks.
|
||||
*/
|
||||
|
||||
@@ -98,7 +98,7 @@ class WC_Cart extends WC_Legacy_Cart {
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->session = new WC_Cart_Session( $this );
|
||||
$this->fees_api = new WC_Cart_Fees( $this );
|
||||
$this->fees_api = new WC_Cart_Fees();
|
||||
|
||||
// Register hooks for the objects.
|
||||
$this->session->init();
|
||||
@@ -120,6 +120,8 @@ class WC_Cart extends WC_Legacy_Cart {
|
||||
public function __clone() {
|
||||
$this->session = clone $this->session;
|
||||
$this->fees_api = clone $this->fees_api;
|
||||
|
||||
$this->session->set_cart( $this );
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -667,7 +669,7 @@ class WC_Cart extends WC_Legacy_Cart {
|
||||
public function get_cart_contents_weight() {
|
||||
$weight = 0.0;
|
||||
|
||||
foreach ( $this->get_cart() as $cart_item_key => $values ) {
|
||||
foreach ( $this->get_cart() as $values ) {
|
||||
if ( $values['data']->has_weight() ) {
|
||||
$weight += (float) $values['data']->get_weight() * $values['quantity'];
|
||||
}
|
||||
@@ -684,7 +686,7 @@ class WC_Cart extends WC_Legacy_Cart {
|
||||
public function get_cart_item_quantities() {
|
||||
$quantities = array();
|
||||
|
||||
foreach ( $this->get_cart() as $cart_item_key => $values ) {
|
||||
foreach ( $this->get_cart() as $values ) {
|
||||
$product = $values['data'];
|
||||
$quantities[ $product->get_stock_managed_by_id() ] = isset( $quantities[ $product->get_stock_managed_by_id() ] ) ? $quantities[ $product->get_stock_managed_by_id() ] + $values['quantity'] : $values['quantity'];
|
||||
}
|
||||
@@ -759,7 +761,7 @@ class WC_Cart extends WC_Legacy_Cart {
|
||||
$product_qty_in_cart = $this->get_cart_item_quantities();
|
||||
$current_session_order_id = isset( WC()->session->order_awaiting_payment ) ? absint( WC()->session->order_awaiting_payment ) : 0;
|
||||
|
||||
foreach ( $this->get_cart() as $cart_item_key => $values ) {
|
||||
foreach ( $this->get_cart() as $values ) {
|
||||
$product = $values['data'];
|
||||
|
||||
// Check stock based on stock-status.
|
||||
@@ -818,7 +820,7 @@ class WC_Cart extends WC_Legacy_Cart {
|
||||
$cross_sells = array();
|
||||
$in_cart = array();
|
||||
if ( ! $this->is_empty() ) {
|
||||
foreach ( $this->get_cart() as $cart_item_key => $values ) {
|
||||
foreach ( $this->get_cart() as $values ) {
|
||||
if ( $values['quantity'] > 0 ) {
|
||||
$cross_sells = array_merge( $values['data']->get_cross_sell_ids(), $cross_sells );
|
||||
$in_cart[] = $values['product_id'];
|
||||
@@ -908,7 +910,7 @@ class WC_Cart extends WC_Legacy_Cart {
|
||||
public function get_cart_item_tax_classes() {
|
||||
$found_tax_classes = array();
|
||||
|
||||
foreach ( WC()->cart->get_cart() as $item ) {
|
||||
foreach ( $this->get_cart() as $item ) {
|
||||
if ( $item['data'] && ( $item['data']->is_taxable() || $item['data']->is_shipping_taxable() ) ) {
|
||||
$found_tax_classes[] = $item['data']->get_tax_class();
|
||||
}
|
||||
@@ -925,7 +927,7 @@ class WC_Cart extends WC_Legacy_Cart {
|
||||
public function get_cart_item_tax_classes_for_shipping() {
|
||||
$found_tax_classes = array();
|
||||
|
||||
foreach ( WC()->cart->get_cart() as $item ) {
|
||||
foreach ( $this->get_cart() as $item ) {
|
||||
if ( $item['data'] && ( $item['data']->is_shipping_taxable() ) ) {
|
||||
$found_tax_classes[] = $item['data']->get_tax_class();
|
||||
}
|
||||
@@ -1536,7 +1538,7 @@ class WC_Cart extends WC_Legacy_Cart {
|
||||
}
|
||||
$needs_shipping = false;
|
||||
|
||||
foreach ( $this->get_cart_contents() as $cart_item_key => $values ) {
|
||||
foreach ( $this->get_cart_contents() as $values ) {
|
||||
if ( $values['data']->needs_shipping() ) {
|
||||
$needs_shipping = true;
|
||||
break;
|
||||
|
||||
@@ -1046,6 +1046,11 @@ class WC_Checkout {
|
||||
// Store Order ID in session so it can be re-used after payment failure.
|
||||
WC()->session->set( 'order_awaiting_payment', $order_id );
|
||||
|
||||
// We save the session early because if the payment gateway hangs
|
||||
// the request will never finish, thus the session data will neved be saved,
|
||||
// and this can lead to duplicate orders if the user submits the order again.
|
||||
WC()->session->save_data();
|
||||
|
||||
// Process Payment.
|
||||
$result = $available_gateways[ $payment_method ]->process_payment( $order_id );
|
||||
|
||||
@@ -1291,7 +1296,7 @@ class WC_Checkout {
|
||||
* Get a posted address field after sanitization and validation.
|
||||
*
|
||||
* @param string $key Field key.
|
||||
* @param string $type Type of address. Available options: 'billing' or 'shipping'.
|
||||
* @param string $type Type of address; 'billing' or 'shipping'.
|
||||
* @return string
|
||||
*/
|
||||
public function get_posted_address_data( $key, $type = 'billing' ) {
|
||||
|
||||
@@ -592,7 +592,7 @@ class WC_Countries {
|
||||
'TW' => "{company}\n{last_name} {first_name}\n{address_1}\n{address_2}\n{state}, {city} {postcode}\n{country}",
|
||||
'UG' => "{name}\n{company}\n{address_1}\n{address_2}\n{city}\n{state}, {country}",
|
||||
'US' => "{name}\n{company}\n{address_1}\n{address_2}\n{city}, {state_code} {postcode}\n{country}",
|
||||
'VN' => "{name}\n{company}\n{address_1}\n{city}\n{country}",
|
||||
'VN' => "{name}\n{company}\n{address_1}\n{address_2}\n{city} {postcode}\n{country}",
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1022,7 +1022,7 @@ class WC_Coupon extends WC_Legacy_Coupon {
|
||||
case self::E_WC_COUPON_USAGE_LIMIT_COUPON_STUCK:
|
||||
if ( is_user_logged_in() && wc_get_page_id( 'myaccount' ) > 0 ) {
|
||||
/* translators: %s: myaccount page link. */
|
||||
$err = sprintf( __( 'Coupon usage limit has been reached. If you were using this coupon just now but order was not complete, you can retry or cancel the order by going to the <a href="%s">my account page</a>.', 'woocommerce' ), wc_get_endpoint_url( 'orders', '', wc_get_page_permalink( 'myaccount' ) ) );
|
||||
$err = sprintf( __( 'Coupon usage limit has been reached. If you were using this coupon just now but your order was not complete, you can retry or cancel the order by going to the <a href="%s">my account page</a>.', 'woocommerce' ), wc_get_endpoint_url( 'orders', '', wc_get_page_permalink( 'myaccount' ) ) );
|
||||
} else {
|
||||
$err = $this->get_coupon_error( self::E_WC_COUPON_USAGE_LIMIT_REACHED );
|
||||
}
|
||||
|
||||
@@ -454,18 +454,27 @@ class WC_Customer extends WC_Legacy_Customer {
|
||||
*
|
||||
* @since 3.0.0
|
||||
* @param string $prop Name of prop to get.
|
||||
* @param string $address billing or shipping.
|
||||
* @param string $context What the value is for. Valid values are 'view' and 'edit'. What the value is for. Valid values are view and edit.
|
||||
* @param string $address_type Type of address; 'billing' or 'shipping'.
|
||||
* @param string $context What the value is for. Valid values are 'view' and 'edit'.
|
||||
* @return mixed
|
||||
*/
|
||||
protected function get_address_prop( $prop, $address = 'billing', $context = 'view' ) {
|
||||
protected function get_address_prop( $prop, $address_type = 'billing', $context = 'view' ) {
|
||||
$value = null;
|
||||
|
||||
if ( array_key_exists( $prop, $this->data[ $address ] ) ) {
|
||||
$value = isset( $this->changes[ $address ][ $prop ] ) ? $this->changes[ $address ][ $prop ] : $this->data[ $address ][ $prop ];
|
||||
if ( array_key_exists( $prop, $this->data[ $address_type ] ) ) {
|
||||
$value = isset( $this->changes[ $address_type ][ $prop ] ) ? $this->changes[ $address_type ][ $prop ] : $this->data[ $address_type ][ $prop ];
|
||||
|
||||
if ( 'view' === $context ) {
|
||||
$value = apply_filters( $this->get_hook_prefix() . $address . '_' . $prop, $value, $this );
|
||||
/**
|
||||
* Filter: 'woocommerce_customer_get_[billing|shipping]_[prop]'
|
||||
*
|
||||
* Allow developers to change the returned value for any customer address property.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @param string $value The address property value.
|
||||
* @param WC_Customer $customer The customer object being read.
|
||||
*/
|
||||
$value = apply_filters( $this->get_hook_prefix() . $address_type . '_' . $prop, $value, $this );
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
@@ -920,18 +929,18 @@ class WC_Customer extends WC_Legacy_Customer {
|
||||
* Sets a prop for a setter method.
|
||||
*
|
||||
* @since 3.0.0
|
||||
* @param string $prop Name of prop to set.
|
||||
* @param string $address Name of address to set. billing or shipping.
|
||||
* @param mixed $value Value of the prop.
|
||||
* @param string $prop Name of prop to set.
|
||||
* @param string $address_type Type of address; 'billing' or 'shipping'.
|
||||
* @param mixed $value Value of the prop.
|
||||
*/
|
||||
protected function set_address_prop( $prop, $address, $value ) {
|
||||
if ( array_key_exists( $prop, $this->data[ $address ] ) ) {
|
||||
protected function set_address_prop( $prop, $address_type, $value ) {
|
||||
if ( array_key_exists( $prop, $this->data[ $address_type ] ) ) {
|
||||
if ( true === $this->object_read ) {
|
||||
if ( $value !== $this->data[ $address ][ $prop ] || ( isset( $this->changes[ $address ] ) && array_key_exists( $prop, $this->changes[ $address ] ) ) ) {
|
||||
$this->changes[ $address ][ $prop ] = $value;
|
||||
if ( $value !== $this->data[ $address_type ][ $prop ] || ( isset( $this->changes[ $address_type ] ) && array_key_exists( $prop, $this->changes[ $address_type ] ) ) ) {
|
||||
$this->changes[ $address_type ][ $prop ] = $value;
|
||||
}
|
||||
} else {
|
||||
$this->data[ $address ][ $prop ] = $value;
|
||||
$this->data[ $address_type ][ $prop ] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,13 +103,13 @@ class WC_Form_Handler {
|
||||
return;
|
||||
}
|
||||
|
||||
$load_address = isset( $wp->query_vars['edit-address'] ) ? wc_edit_address_i18n( sanitize_title( $wp->query_vars['edit-address'] ), true ) : 'billing';
|
||||
$address_type = isset( $wp->query_vars['edit-address'] ) ? wc_edit_address_i18n( sanitize_title( $wp->query_vars['edit-address'] ), true ) : 'billing';
|
||||
|
||||
if ( ! isset( $_POST[ $load_address . '_country' ] ) ) {
|
||||
if ( ! isset( $_POST[ $address_type . '_country' ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$address = WC()->countries->get_address_fields( wc_clean( wp_unslash( $_POST[ $load_address . '_country' ] ) ), $load_address . '_' );
|
||||
$address = WC()->countries->get_address_fields( wc_clean( wp_unslash( $_POST[ $address_type . '_country' ] ) ), $address_type . '_' );
|
||||
|
||||
foreach ( $address as $key => $field ) {
|
||||
if ( ! isset( $field['type'] ) ) {
|
||||
@@ -138,7 +138,7 @@ class WC_Form_Handler {
|
||||
foreach ( $field['validate'] as $rule ) {
|
||||
switch ( $rule ) {
|
||||
case 'postcode':
|
||||
$country = wc_clean( wp_unslash( $_POST[ $load_address . '_country' ] ) );
|
||||
$country = wc_clean( wp_unslash( $_POST[ $address_type . '_country' ] ) );
|
||||
$value = wc_format_postcode( $value, $country );
|
||||
|
||||
if ( '' !== $value && ! WC_Validation::is_postcode( $value, $country ) ) {
|
||||
@@ -191,12 +191,13 @@ class WC_Form_Handler {
|
||||
*
|
||||
* Allow developers to add custom validation logic and throw an error to prevent save.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @param int $user_id User ID being saved.
|
||||
* @param string $load_address Type of address e.g. billing or shipping.
|
||||
* @param string $address_type Type of address; 'billing' or 'shipping'.
|
||||
* @param array $address The address fields.
|
||||
* @param WC_Customer $customer The customer object being saved. @since 3.6.0
|
||||
* @param WC_Customer $customer The customer object being saved.
|
||||
*/
|
||||
do_action( 'woocommerce_after_save_address_validation', $user_id, $load_address, $address, $customer );
|
||||
do_action( 'woocommerce_after_save_address_validation', $user_id, $address_type, $address, $customer );
|
||||
|
||||
if ( 0 < wc_notice_count( 'error' ) ) {
|
||||
return;
|
||||
@@ -206,7 +207,16 @@ class WC_Form_Handler {
|
||||
|
||||
wc_add_notice( __( 'Address changed successfully.', 'woocommerce' ) );
|
||||
|
||||
do_action( 'woocommerce_customer_save_address', $user_id, $load_address );
|
||||
/**
|
||||
* Hook: woocommerce_customer_save_address.
|
||||
*
|
||||
* Fires after a customer address has been saved.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @param int $user_id User ID being saved.
|
||||
* @param string $address_type Type of address; 'billing' or 'shipping'.
|
||||
*/
|
||||
do_action( 'woocommerce_customer_save_address', $user_id, $address_type );
|
||||
|
||||
wp_safe_redirect( wc_get_endpoint_url( 'edit-address', '', wc_get_page_permalink( 'myaccount' ) ) );
|
||||
exit;
|
||||
|
||||
@@ -120,7 +120,7 @@ class WC_Frontend_Scripts {
|
||||
* @param string $version String specifying script version number, if it has one, which is added to the URL as a query string for cache busting purposes. If version is set to false, a version number is automatically added equal to current installed WordPress version. If set to null, no version is added.
|
||||
* @param boolean $in_footer Whether to enqueue the script before </body> instead of in the <head>. Default 'false'.
|
||||
*/
|
||||
private static function register_script( $handle, $path, $deps = array( 'jquery' ), $version = WC_VERSION, $in_footer = true ) {
|
||||
private static function register_script( $handle, $path, $deps = array( 'jquery' ), $version = WC_VERSION, $in_footer = array( 'strategy' => 'defer' ) ) {
|
||||
self::$scripts[] = $handle;
|
||||
wp_register_script( $handle, $path, $deps, $version, $in_footer );
|
||||
}
|
||||
@@ -135,7 +135,7 @@ class WC_Frontend_Scripts {
|
||||
* @param string $version String specifying script version number, if it has one, which is added to the URL as a query string for cache busting purposes. If version is set to false, a version number is automatically added equal to current installed WordPress version. If set to null, no version is added.
|
||||
* @param boolean $in_footer Whether to enqueue the script before </body> instead of in the <head>. Default 'false'.
|
||||
*/
|
||||
private static function enqueue_script( $handle, $path = '', $deps = array( 'jquery' ), $version = WC_VERSION, $in_footer = true ) {
|
||||
private static function enqueue_script( $handle, $path = '', $deps = array( 'jquery' ), $version = WC_VERSION, $in_footer = array( 'strategy' => 'defer' ) ) {
|
||||
if ( ! in_array( $handle, self::$scripts, true ) && $path ) {
|
||||
self::register_script( $handle, $path, $deps, $version, $in_footer );
|
||||
}
|
||||
|
||||
@@ -8,12 +8,15 @@
|
||||
|
||||
use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Admin\Notes\Notes;
|
||||
use Automattic\WooCommerce\Internal\DataStores\Orders\{ CustomOrdersTableController, DataSynchronizer, OrdersTableDataStore };
|
||||
use Automattic\WooCommerce\Internal\Features\FeaturesController;
|
||||
use Automattic\WooCommerce\Internal\ProductAttributesLookup\DataRegenerator;
|
||||
use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Register as Download_Directories;
|
||||
use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Synchronize as Download_Directories_Sync;
|
||||
use Automattic\WooCommerce\Internal\Utilities\DatabaseUtil;
|
||||
use Automattic\WooCommerce\Internal\WCCom\ConnectionHelper as WCConnectionHelper;
|
||||
use Automattic\WooCommerce\Internal\Traits\AccessiblePrivateMethods;
|
||||
use Automattic\WooCommerce\Utilities\OrderUtil;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
@@ -234,6 +237,9 @@ class WC_Install {
|
||||
'7.7.0' => array(
|
||||
'wc_update_770_remove_multichannel_marketing_feature_options',
|
||||
),
|
||||
'8.1.0' => array(
|
||||
'wc_update_810_migrate_transactional_metadata_for_hpos',
|
||||
),
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -249,6 +255,7 @@ class WC_Install {
|
||||
public static function init() {
|
||||
add_action( 'init', array( __CLASS__, 'check_version' ), 5 );
|
||||
add_action( 'init', array( __CLASS__, 'manual_database_update' ), 20 );
|
||||
add_action( 'woocommerce_newly_installed', array( __CLASS__, 'maybe_enable_hpos' ), 20 );
|
||||
add_action( 'admin_init', array( __CLASS__, 'wc_admin_db_update_notice' ) );
|
||||
add_action( 'admin_init', array( __CLASS__, 'add_admin_note_after_page_created' ) );
|
||||
add_action( 'woocommerce_run_update_callback', array( __CLASS__, 'run_update_callback' ) );
|
||||
@@ -480,9 +487,27 @@ class WC_Install {
|
||||
self::create_tables();
|
||||
}
|
||||
|
||||
$schema = self::get_schema();
|
||||
|
||||
$hpos_settings = filter_var_array(
|
||||
array(
|
||||
'cot' => get_option( CustomOrdersTableController::CUSTOM_ORDERS_TABLE_USAGE_ENABLED_OPTION ),
|
||||
'data_sync' => get_option( DataSynchronizer::ORDERS_DATA_SYNC_ENABLED_OPTION ),
|
||||
),
|
||||
array(
|
||||
'cot' => FILTER_VALIDATE_BOOLEAN,
|
||||
'data_sync' => FILTER_VALIDATE_BOOLEAN,
|
||||
)
|
||||
);
|
||||
if ( in_array( true, $hpos_settings, true ) ) {
|
||||
$schema .= wc_get_container()
|
||||
->get( OrdersTableDataStore::class )
|
||||
->get_database_schema();
|
||||
}
|
||||
|
||||
$missing_tables = wc_get_container()
|
||||
->get( DatabaseUtil::class )
|
||||
->get_missing_tables( self::get_schema() );
|
||||
->get_missing_tables( $schema );
|
||||
|
||||
if ( 0 < count( $missing_tables ) ) {
|
||||
if ( $modify_notice ) {
|
||||
@@ -742,15 +767,21 @@ class WC_Install {
|
||||
* Determines the cart shortcode tag used for the cart page.
|
||||
*
|
||||
* @since 2.1.0
|
||||
* @deprecated 8.3.0 This filter is deprecated and will be removed in future versions.
|
||||
*/
|
||||
$cart_shortcode = apply_filters( 'woocommerce_cart_shortcode_tag', 'woocommerce_cart' );
|
||||
$cart_shortcode = apply_filters_deprecated( 'woocommerce_cart_shortcode_tag', array( '' ), '8.3.0', 'woocommerce_create_pages' );
|
||||
|
||||
$cart_page_content = empty( $cart_shortcode ) ? self::get_cart_block_content() : '<!-- wp:shortcode -->[' . $cart_shortcode . ']<!-- /wp:shortcode -->';
|
||||
|
||||
/**
|
||||
* Determines the checkout shortcode tag used on the checkout page.
|
||||
*
|
||||
* @since 2.1.0
|
||||
* @deprecated 8.3.0 This filter is deprecated and will be removed in future versions.
|
||||
*/
|
||||
$checkout_shortcode = apply_filters( 'woocommerce_checkout_shortcode_tag', 'woocommerce_checkout' );
|
||||
$checkout_shortcode = apply_filters_deprecated( 'woocommerce_checkout_shortcode_tag', array( '' ), '8.3.0', 'woocommerce_create_pages' );
|
||||
|
||||
$checkout_page_content = empty( $checkout_shortcode ) ? self::get_checkout_block_content() : '<!-- wp:shortcode -->[' . $checkout_shortcode . ']<!-- /wp:shortcode -->';
|
||||
|
||||
/**
|
||||
* Determines the my account shortcode tag used on the my account page.
|
||||
@@ -775,12 +806,12 @@ class WC_Install {
|
||||
'cart' => array(
|
||||
'name' => _x( 'cart', 'Page slug', 'woocommerce' ),
|
||||
'title' => _x( 'Cart', 'Page title', 'woocommerce' ),
|
||||
'content' => '<!-- wp:shortcode -->[' . $cart_shortcode . ']<!-- /wp:shortcode -->',
|
||||
'content' => $cart_page_content,
|
||||
),
|
||||
'checkout' => array(
|
||||
'name' => _x( 'checkout', 'Page slug', 'woocommerce' ),
|
||||
'title' => _x( 'Checkout', 'Page title', 'woocommerce' ),
|
||||
'content' => '<!-- wp:shortcode -->[' . $checkout_shortcode . ']<!-- /wp:shortcode -->',
|
||||
'content' => $checkout_page_content,
|
||||
),
|
||||
'myaccount' => array(
|
||||
'name' => _x( 'my-account', 'Page slug', 'woocommerce' ),
|
||||
@@ -859,6 +890,51 @@ class WC_Install {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable HPOS by default for new shops.
|
||||
*
|
||||
* @since 8.2.0
|
||||
*/
|
||||
public static function maybe_enable_hpos() {
|
||||
if ( self::should_enable_hpos_for_new_shop() ) {
|
||||
$feature_controller = wc_get_container()->get( FeaturesController::class );
|
||||
$feature_controller->change_feature_enable( 'custom_order_tables', true );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks whether HPOS should be enabled for new shops.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private static function should_enable_hpos_for_new_shop() {
|
||||
if ( ! did_action( 'woocommerce_init' ) && ! doing_action( 'woocommerce_init' ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$feature_controller = wc_get_container()->get( FeaturesController::class );
|
||||
|
||||
if ( OrderUtil::custom_orders_table_usage_is_enabled() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( ! empty( wc_get_orders( array( 'limit' => 1 ) ) ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$plugin_compat_info = $feature_controller->get_compatible_plugins_for_feature( 'custom_order_tables', true );
|
||||
if ( ! empty( $plugin_compat_info['incompatible'] ) || ! empty( $plugin_compat_info['uncertain'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter to enable HPOS by default for new shops.
|
||||
*
|
||||
* @since 8.2.0
|
||||
*/
|
||||
return apply_filters( 'woocommerce_enable_hpos_by_default_for_new_shops', true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete obsolete notes.
|
||||
*/
|
||||
@@ -1142,15 +1218,17 @@ class WC_Install {
|
||||
$collate = $wpdb->get_charset_collate();
|
||||
}
|
||||
|
||||
/*
|
||||
* Indexes have a maximum size of 767 bytes. Historically, we haven't need to be concerned about that.
|
||||
* As of WP 4.2, however, they moved to utf8mb4, which uses 4 bytes per character. This means that an index which
|
||||
* used to have room for floor(767/3) = 255 characters, now only has room for floor(767/4) = 191 characters.
|
||||
*/
|
||||
$max_index_length = 191;
|
||||
$max_index_length = wc_get_container()->get( DatabaseUtil::class )->get_max_index_length();
|
||||
|
||||
$product_attributes_lookup_table_creation_sql = wc_get_container()->get( DataRegenerator::class )->get_table_creation_sql();
|
||||
|
||||
$feature_controller = wc_get_container()->get( FeaturesController::class );
|
||||
$hpos_enabled =
|
||||
$feature_controller->feature_is_enabled( DataSynchronizer::ORDERS_DATA_SYNC_ENABLED_OPTION ) || $feature_controller->feature_is_enabled( CustomOrdersTableController::CUSTOM_ORDERS_TABLE_USAGE_ENABLED_OPTION ) ||
|
||||
self::should_enable_hpos_for_new_shop()
|
||||
;
|
||||
$hpos_table_schema = $hpos_enabled ? wc_get_container()->get( OrdersTableDataStore::class )->get_database_schema() : '';
|
||||
|
||||
$tables = "
|
||||
CREATE TABLE {$wpdb->prefix}woocommerce_sessions (
|
||||
session_id bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
@@ -1494,6 +1572,7 @@ CREATE TABLE {$wpdb->prefix}wc_category_lookup (
|
||||
category_id bigint(20) unsigned NOT NULL,
|
||||
PRIMARY KEY (category_tree_id,category_id)
|
||||
) $collate;
|
||||
$hpos_table_schema;
|
||||
";
|
||||
|
||||
return $tables;
|
||||
@@ -2359,6 +2438,182 @@ EOT;
|
||||
add_option( 'woocommerce_refund_returns_page_created', $page_id, '', false );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Cart block content.
|
||||
*
|
||||
* @since 8.3.0
|
||||
* @return string
|
||||
*/
|
||||
protected static function get_cart_block_content() {
|
||||
return '<!-- wp:woocommerce/cart -->
|
||||
<div class="wp-block-woocommerce-cart alignwide is-loading"><!-- wp:woocommerce/filled-cart-block -->
|
||||
<div class="wp-block-woocommerce-filled-cart-block"><!-- wp:woocommerce/cart-items-block -->
|
||||
<div class="wp-block-woocommerce-cart-items-block"><!-- wp:woocommerce/cart-line-items-block -->
|
||||
<div class="wp-block-woocommerce-cart-line-items-block"></div>
|
||||
<!-- /wp:woocommerce/cart-line-items-block -->
|
||||
|
||||
<!-- wp:woocommerce/cart-cross-sells-block -->
|
||||
<div class="wp-block-woocommerce-cart-cross-sells-block"><!-- wp:heading {"fontSize":"large"} -->
|
||||
<h2 class="wp-block-heading has-large-font-size">' . __( 'You may be interested in…', 'woocommerce' ) . '</h2>
|
||||
<!-- /wp:heading -->
|
||||
|
||||
<!-- wp:woocommerce/cart-cross-sells-products-block -->
|
||||
<div class="wp-block-woocommerce-cart-cross-sells-products-block"></div>
|
||||
<!-- /wp:woocommerce/cart-cross-sells-products-block --></div>
|
||||
<!-- /wp:woocommerce/cart-cross-sells-block --></div>
|
||||
<!-- /wp:woocommerce/cart-items-block -->
|
||||
|
||||
<!-- wp:woocommerce/cart-totals-block -->
|
||||
<div class="wp-block-woocommerce-cart-totals-block"><!-- wp:woocommerce/cart-order-summary-block -->
|
||||
<div class="wp-block-woocommerce-cart-order-summary-block"><!-- wp:woocommerce/cart-order-summary-heading-block -->
|
||||
<div class="wp-block-woocommerce-cart-order-summary-heading-block"></div>
|
||||
<!-- /wp:woocommerce/cart-order-summary-heading-block -->
|
||||
|
||||
<!-- wp:woocommerce/cart-order-summary-coupon-form-block -->
|
||||
<div class="wp-block-woocommerce-cart-order-summary-coupon-form-block"></div>
|
||||
<!-- /wp:woocommerce/cart-order-summary-coupon-form-block -->
|
||||
|
||||
<!-- wp:woocommerce/cart-order-summary-subtotal-block -->
|
||||
<div class="wp-block-woocommerce-cart-order-summary-subtotal-block"></div>
|
||||
<!-- /wp:woocommerce/cart-order-summary-subtotal-block -->
|
||||
|
||||
<!-- wp:woocommerce/cart-order-summary-fee-block -->
|
||||
<div class="wp-block-woocommerce-cart-order-summary-fee-block"></div>
|
||||
<!-- /wp:woocommerce/cart-order-summary-fee-block -->
|
||||
|
||||
<!-- wp:woocommerce/cart-order-summary-discount-block -->
|
||||
<div class="wp-block-woocommerce-cart-order-summary-discount-block"></div>
|
||||
<!-- /wp:woocommerce/cart-order-summary-discount-block -->
|
||||
|
||||
<!-- wp:woocommerce/cart-order-summary-shipping-block -->
|
||||
<div class="wp-block-woocommerce-cart-order-summary-shipping-block"></div>
|
||||
<!-- /wp:woocommerce/cart-order-summary-shipping-block -->
|
||||
|
||||
<!-- wp:woocommerce/cart-order-summary-taxes-block -->
|
||||
<div class="wp-block-woocommerce-cart-order-summary-taxes-block"></div>
|
||||
<!-- /wp:woocommerce/cart-order-summary-taxes-block --></div>
|
||||
<!-- /wp:woocommerce/cart-order-summary-block -->
|
||||
|
||||
<!-- wp:woocommerce/cart-express-payment-block -->
|
||||
<div class="wp-block-woocommerce-cart-express-payment-block"></div>
|
||||
<!-- /wp:woocommerce/cart-express-payment-block -->
|
||||
|
||||
<!-- wp:woocommerce/proceed-to-checkout-block -->
|
||||
<div class="wp-block-woocommerce-proceed-to-checkout-block"></div>
|
||||
<!-- /wp:woocommerce/proceed-to-checkout-block -->
|
||||
|
||||
<!-- wp:woocommerce/cart-accepted-payment-methods-block -->
|
||||
<div class="wp-block-woocommerce-cart-accepted-payment-methods-block"></div>
|
||||
<!-- /wp:woocommerce/cart-accepted-payment-methods-block --></div>
|
||||
<!-- /wp:woocommerce/cart-totals-block --></div>
|
||||
<!-- /wp:woocommerce/filled-cart-block -->
|
||||
|
||||
<!-- wp:woocommerce/empty-cart-block -->
|
||||
<div class="wp-block-woocommerce-empty-cart-block"><!-- wp:heading {"textAlign":"center","className":"with-empty-cart-icon wc-block-cart__empty-cart__title"} -->
|
||||
<h2 class="wp-block-heading has-text-align-center with-empty-cart-icon wc-block-cart__empty-cart__title">' . __( 'Your cart is currently empty!', 'woocommerce' ) . '</h2>
|
||||
<!-- /wp:heading -->
|
||||
|
||||
<!-- wp:separator {"className":"is-style-dots"} -->
|
||||
<hr class="wp-block-separator has-alpha-channel-opacity is-style-dots"/>
|
||||
<!-- /wp:separator -->
|
||||
|
||||
<!-- wp:heading {"textAlign":"center"} -->
|
||||
<h2 class="wp-block-heading has-text-align-center">' . __( 'New in store', 'woocommerce' ) . '</h2>
|
||||
<!-- /wp:heading -->
|
||||
|
||||
<!-- wp:woocommerce/product-new {"columns":4,"rows":1} /--></div>
|
||||
<!-- /wp:woocommerce/empty-cart-block --></div>
|
||||
<!-- /wp:woocommerce/cart -->';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Checkout block content.
|
||||
*
|
||||
* @since 8.3.0
|
||||
* @return string
|
||||
*/
|
||||
protected static function get_checkout_block_content() {
|
||||
return '<!-- wp:woocommerce/checkout -->
|
||||
<div class="wp-block-woocommerce-checkout alignwide wc-block-checkout is-loading"><!-- wp:woocommerce/checkout-fields-block -->
|
||||
<div class="wp-block-woocommerce-checkout-fields-block"><!-- wp:woocommerce/checkout-express-payment-block -->
|
||||
<div class="wp-block-woocommerce-checkout-express-payment-block"></div>
|
||||
<!-- /wp:woocommerce/checkout-express-payment-block -->
|
||||
|
||||
<!-- wp:woocommerce/checkout-contact-information-block -->
|
||||
<div class="wp-block-woocommerce-checkout-contact-information-block"></div>
|
||||
<!-- /wp:woocommerce/checkout-contact-information-block -->
|
||||
|
||||
<!-- wp:woocommerce/checkout-shipping-method-block -->
|
||||
<div class="wp-block-woocommerce-checkout-shipping-method-block"></div>
|
||||
<!-- /wp:woocommerce/checkout-shipping-method-block -->
|
||||
|
||||
<!-- wp:woocommerce/checkout-pickup-options-block -->
|
||||
<div class="wp-block-woocommerce-checkout-pickup-options-block"></div>
|
||||
<!-- /wp:woocommerce/checkout-pickup-options-block -->
|
||||
|
||||
<!-- wp:woocommerce/checkout-shipping-address-block -->
|
||||
<div class="wp-block-woocommerce-checkout-shipping-address-block"></div>
|
||||
<!-- /wp:woocommerce/checkout-shipping-address-block -->
|
||||
|
||||
<!-- wp:woocommerce/checkout-billing-address-block -->
|
||||
<div class="wp-block-woocommerce-checkout-billing-address-block"></div>
|
||||
<!-- /wp:woocommerce/checkout-billing-address-block -->
|
||||
|
||||
<!-- wp:woocommerce/checkout-shipping-methods-block -->
|
||||
<div class="wp-block-woocommerce-checkout-shipping-methods-block"></div>
|
||||
<!-- /wp:woocommerce/checkout-shipping-methods-block -->
|
||||
|
||||
<!-- wp:woocommerce/checkout-payment-block -->
|
||||
<div class="wp-block-woocommerce-checkout-payment-block"></div>
|
||||
<!-- /wp:woocommerce/checkout-payment-block -->
|
||||
|
||||
<!-- wp:woocommerce/checkout-order-note-block -->
|
||||
<div class="wp-block-woocommerce-checkout-order-note-block"></div>
|
||||
<!-- /wp:woocommerce/checkout-order-note-block -->
|
||||
|
||||
<!-- wp:woocommerce/checkout-terms-block -->
|
||||
<div class="wp-block-woocommerce-checkout-terms-block"></div>
|
||||
<!-- /wp:woocommerce/checkout-terms-block -->
|
||||
|
||||
<!-- wp:woocommerce/checkout-actions-block -->
|
||||
<div class="wp-block-woocommerce-checkout-actions-block"></div>
|
||||
<!-- /wp:woocommerce/checkout-actions-block --></div>
|
||||
<!-- /wp:woocommerce/checkout-fields-block -->
|
||||
|
||||
<!-- wp:woocommerce/checkout-totals-block -->
|
||||
<div class="wp-block-woocommerce-checkout-totals-block"><!-- wp:woocommerce/checkout-order-summary-block -->
|
||||
<div class="wp-block-woocommerce-checkout-order-summary-block"><!-- wp:woocommerce/checkout-order-summary-cart-items-block -->
|
||||
<div class="wp-block-woocommerce-checkout-order-summary-cart-items-block"></div>
|
||||
<!-- /wp:woocommerce/checkout-order-summary-cart-items-block -->
|
||||
|
||||
<!-- wp:woocommerce/checkout-order-summary-coupon-form-block -->
|
||||
<div class="wp-block-woocommerce-checkout-order-summary-coupon-form-block"></div>
|
||||
<!-- /wp:woocommerce/checkout-order-summary-coupon-form-block -->
|
||||
|
||||
<!-- wp:woocommerce/checkout-order-summary-subtotal-block -->
|
||||
<div class="wp-block-woocommerce-checkout-order-summary-subtotal-block"></div>
|
||||
<!-- /wp:woocommerce/checkout-order-summary-subtotal-block -->
|
||||
|
||||
<!-- wp:woocommerce/checkout-order-summary-fee-block -->
|
||||
<div class="wp-block-woocommerce-checkout-order-summary-fee-block"></div>
|
||||
<!-- /wp:woocommerce/checkout-order-summary-fee-block -->
|
||||
|
||||
<!-- wp:woocommerce/checkout-order-summary-discount-block -->
|
||||
<div class="wp-block-woocommerce-checkout-order-summary-discount-block"></div>
|
||||
<!-- /wp:woocommerce/checkout-order-summary-discount-block -->
|
||||
|
||||
<!-- wp:woocommerce/checkout-order-summary-shipping-block -->
|
||||
<div class="wp-block-woocommerce-checkout-order-summary-shipping-block"></div>
|
||||
<!-- /wp:woocommerce/checkout-order-summary-shipping-block -->
|
||||
|
||||
<!-- wp:woocommerce/checkout-order-summary-taxes-block -->
|
||||
<div class="wp-block-woocommerce-checkout-order-summary-taxes-block"></div>
|
||||
<!-- /wp:woocommerce/checkout-order-summary-taxes-block --></div>
|
||||
<!-- /wp:woocommerce/checkout-order-summary-block --></div>
|
||||
<!-- /wp:woocommerce/checkout-totals-block --></div>
|
||||
<!-- /wp:woocommerce/checkout -->';
|
||||
}
|
||||
}
|
||||
|
||||
WC_Install::init();
|
||||
|
||||
@@ -557,18 +557,27 @@ class WC_Order extends WC_Abstract_Order {
|
||||
*
|
||||
* @since 3.0.0
|
||||
* @param string $prop Name of prop to get.
|
||||
* @param string $address billing or shipping.
|
||||
* @param string $address_type Type of address; 'billing' or 'shipping'.
|
||||
* @param string $context What the value is for. Valid values are view and edit.
|
||||
* @return mixed
|
||||
*/
|
||||
protected function get_address_prop( $prop, $address = 'billing', $context = 'view' ) {
|
||||
protected function get_address_prop( $prop, $address_type = 'billing', $context = 'view' ) {
|
||||
$value = null;
|
||||
|
||||
if ( array_key_exists( $prop, $this->data[ $address ] ) ) {
|
||||
$value = isset( $this->changes[ $address ][ $prop ] ) ? $this->changes[ $address ][ $prop ] : $this->data[ $address ][ $prop ];
|
||||
if ( array_key_exists( $prop, $this->data[ $address_type ] ) ) {
|
||||
$value = isset( $this->changes[ $address_type ][ $prop ] ) ? $this->changes[ $address_type ][ $prop ] : $this->data[ $address_type ][ $prop ];
|
||||
|
||||
if ( 'view' === $context ) {
|
||||
$value = apply_filters( $this->get_hook_prefix() . $address . '_' . $prop, $value, $this );
|
||||
/**
|
||||
* Filter: 'woocommerce_order_get_[billing|shipping]_[prop]'
|
||||
*
|
||||
* Allow developers to change the returned value for any order address property.
|
||||
*
|
||||
* @since 3.6.0
|
||||
* @param string $value The address property value.
|
||||
* @param WC_Order $order The order object being read.
|
||||
*/
|
||||
$value = apply_filters( $this->get_hook_prefix() . $address_type . '_' . $prop, $value, $this );
|
||||
}
|
||||
}
|
||||
return $value;
|
||||
@@ -896,11 +905,20 @@ class WC_Order extends WC_Abstract_Order {
|
||||
* Note: Merges raw data with get_prop data so changes are returned too.
|
||||
*
|
||||
* @since 2.4.0
|
||||
* @param string $type Billing or shipping. Anything else besides 'billing' will return shipping address.
|
||||
* @param string $address_type Type of address; 'billing' or 'shipping'.
|
||||
* @return array The stored address after filter.
|
||||
*/
|
||||
public function get_address( $type = 'billing' ) {
|
||||
return apply_filters( 'woocommerce_get_order_address', array_merge( $this->data[ $type ], $this->get_prop( $type, 'view' ) ), $type, $this );
|
||||
public function get_address( $address_type = 'billing' ) {
|
||||
/**
|
||||
* Filter: 'woocommerce_get_order_address'
|
||||
*
|
||||
* Allow developers to change the returned value for an order's billing or shipping address.
|
||||
*
|
||||
* @since 2.4.0
|
||||
* @param array $address_data The raw address data merged with the data from get_prop.
|
||||
* @param string $address_type Type of address; 'billing' or 'shipping'.
|
||||
*/
|
||||
return apply_filters( 'woocommerce_get_order_address', array_merge( $this->data[ $address_type ], $this->get_prop( $address_type, 'view' ) ), $address_type, $this );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1067,17 +1085,17 @@ class WC_Order extends WC_Abstract_Order {
|
||||
*
|
||||
* @since 3.0.0
|
||||
* @param string $prop Name of prop to set.
|
||||
* @param string $address Name of address to set. billing or shipping.
|
||||
* @param string $address_type Type of address; 'billing' or 'shipping'.
|
||||
* @param mixed $value Value of the prop.
|
||||
*/
|
||||
protected function set_address_prop( $prop, $address, $value ) {
|
||||
if ( array_key_exists( $prop, $this->data[ $address ] ) ) {
|
||||
protected function set_address_prop( $prop, $address_type, $value ) {
|
||||
if ( array_key_exists( $prop, $this->data[ $address_type ] ) ) {
|
||||
if ( true === $this->object_read ) {
|
||||
if ( $value !== $this->data[ $address ][ $prop ] || ( isset( $this->changes[ $address ] ) && array_key_exists( $prop, $this->changes[ $address ] ) ) ) {
|
||||
$this->changes[ $address ][ $prop ] = $value;
|
||||
if ( $value !== $this->data[ $address_type ][ $prop ] || ( isset( $this->changes[ $address_type ] ) && array_key_exists( $prop, $this->changes[ $address_type ] ) ) ) {
|
||||
$this->changes[ $address_type ][ $prop ] = $value;
|
||||
}
|
||||
} else {
|
||||
$this->data[ $address ][ $prop ] = $value;
|
||||
$this->data[ $address_type ][ $prop ] = $value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1784,6 +1802,15 @@ class WC_Order extends WC_Abstract_Order {
|
||||
* @return string
|
||||
*/
|
||||
public function get_cancel_order_url( $redirect = '' ) {
|
||||
/**
|
||||
* Filter the URL to cancel the order in the frontend.
|
||||
*
|
||||
* @since 2.2.0
|
||||
*
|
||||
* @param string $url
|
||||
* @param WC_Order $order Order data.
|
||||
* @param string $redirect Redirect URL.
|
||||
*/
|
||||
return apply_filters(
|
||||
'woocommerce_get_cancel_order_url',
|
||||
wp_nonce_url(
|
||||
@@ -1797,7 +1824,9 @@ class WC_Order extends WC_Abstract_Order {
|
||||
$this->get_cancel_endpoint()
|
||||
),
|
||||
'woocommerce-cancel_order'
|
||||
)
|
||||
),
|
||||
$this,
|
||||
$redirect
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1808,6 +1837,15 @@ class WC_Order extends WC_Abstract_Order {
|
||||
* @return string The unescaped cancel-order URL.
|
||||
*/
|
||||
public function get_cancel_order_url_raw( $redirect = '' ) {
|
||||
/**
|
||||
* Filter the raw URL to cancel the order in the frontend.
|
||||
*
|
||||
* @since 2.2.0
|
||||
*
|
||||
* @param string $url
|
||||
* @param WC_Order $order Order data.
|
||||
* @param string $redirect Redirect URL.
|
||||
*/
|
||||
return apply_filters(
|
||||
'woocommerce_get_cancel_order_url_raw',
|
||||
add_query_arg(
|
||||
@@ -1819,7 +1857,9 @@ class WC_Order extends WC_Abstract_Order {
|
||||
'_wpnonce' => wp_create_nonce( 'woocommerce-cancel_order' ),
|
||||
),
|
||||
$this->get_cancel_endpoint()
|
||||
)
|
||||
),
|
||||
$this,
|
||||
$redirect
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ use Automattic\Jetpack\Constants;
|
||||
use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
|
||||
use Automattic\WooCommerce\Utilities\{ FeaturesUtil, OrderUtil, PluginUtil };
|
||||
use Automattic\WooCommerce\Internal\Utilities\BlocksUtil;
|
||||
use Automattic\WooCommerce\Proxies\LegacyProxy;
|
||||
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
@@ -311,7 +312,7 @@ class WC_Tracker {
|
||||
include ABSPATH . '/wp-admin/includes/plugin.php';
|
||||
}
|
||||
|
||||
$plugins = get_plugins();
|
||||
$plugins = wc_get_container()->get( LegacyProxy::class )->call_function( 'get_plugins' );
|
||||
$active_plugins_keys = get_option( 'active_plugins', array() );
|
||||
$active_plugins = array();
|
||||
|
||||
|
||||
@@ -997,9 +997,11 @@ class WC_Webhook extends WC_Legacy_Webhook {
|
||||
),
|
||||
'order.deleted' => array(
|
||||
'wp_trash_post',
|
||||
'woocommerce_trash_order',
|
||||
),
|
||||
'order.restored' => array(
|
||||
'untrashed_post',
|
||||
'woocommerce_untrash_order',
|
||||
),
|
||||
'product.created' => array(
|
||||
'woocommerce_process_product_meta',
|
||||
|
||||
@@ -19,6 +19,7 @@ use Automattic\WooCommerce\Internal\ProductDownloads\ApprovedDirectories\Registe
|
||||
use Automattic\WooCommerce\Internal\RestockRefundedItemsAdjuster;
|
||||
use Automattic\WooCommerce\Internal\Settings\OptionSanitizer;
|
||||
use Automattic\WooCommerce\Internal\Utilities\WebhookUtil;
|
||||
use Automattic\WooCommerce\Internal\Admin\Marketplace;
|
||||
use Automattic\WooCommerce\Proxies\LegacyProxy;
|
||||
|
||||
/**
|
||||
@@ -33,7 +34,7 @@ final class WooCommerce {
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $version = '8.0.1';
|
||||
public $version = '8.3.0';
|
||||
|
||||
/**
|
||||
* WooCommerce Schema version.
|
||||
@@ -259,6 +260,7 @@ final class WooCommerce {
|
||||
$container->get( BatchProcessingController::class );
|
||||
$container->get( FeaturesController::class );
|
||||
$container->get( WebhookUtil::class );
|
||||
$container->get( Marketplace::class );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -315,9 +317,12 @@ final class WooCommerce {
|
||||
$this->define( 'WC_LOG_DIR', $upload_dir['basedir'] . '/wc-logs/' );
|
||||
$this->define( 'WC_SESSION_CACHE_GROUP', 'wc_session_id' );
|
||||
$this->define( 'WC_TEMPLATE_DEBUG_MODE', false );
|
||||
|
||||
// These three are kept defined for compatibility, but are no longer used.
|
||||
$this->define( 'WC_NOTICE_MIN_PHP_VERSION', '7.2' );
|
||||
$this->define( 'WC_NOTICE_MIN_WP_VERSION', '5.2' );
|
||||
$this->define( 'WC_PHP_MIN_REQUIREMENTS_NOTICE', 'wp_php_min_requirements_' . WC_NOTICE_MIN_PHP_VERSION . '_' . WC_NOTICE_MIN_WP_VERSION );
|
||||
|
||||
/** Define if we're checking against major, minor or no versions in the following places:
|
||||
* - plugin screen in WP Admin (displaying extra warning when updating to new major versions)
|
||||
* - System Status Report ('Installed version not tested with active version of WooCommerce' warning)
|
||||
|
||||
+20
-5
@@ -706,7 +706,7 @@ abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP impleme
|
||||
*
|
||||
* @param WC_Abstract_Order $order Order object.
|
||||
*/
|
||||
private function update_order_meta_from_object( $order ) {
|
||||
protected function update_order_meta_from_object( $order ) {
|
||||
if ( is_null( $order->get_meta() ) ) {
|
||||
return;
|
||||
}
|
||||
@@ -715,13 +715,24 @@ abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP impleme
|
||||
|
||||
foreach ( $order->get_meta_data() as $meta_data ) {
|
||||
if ( isset( $existing_meta_data[ $meta_data->key ] ) ) {
|
||||
if ( $existing_meta_data[ $meta_data->key ] === $meta_data->value ) {
|
||||
// We don't know if the meta is single or array, so we assume it to be an array.
|
||||
$meta_value = is_array( $meta_data->value ) ? $meta_data->value : array( $meta_data->value );
|
||||
|
||||
if ( $existing_meta_data[ $meta_data->key ] === $meta_value ) {
|
||||
unset( $existing_meta_data[ $meta_data->key ] );
|
||||
continue;
|
||||
}
|
||||
|
||||
unset( $existing_meta_data[ $meta_data->key ] );
|
||||
delete_post_meta( $order->get_id(), $meta_data->key );
|
||||
if ( is_array( $existing_meta_data[ $meta_data->key ] ) ) {
|
||||
$value_index = array_search( maybe_serialize( $meta_data->value ), $existing_meta_data[ $meta_data->key ], true );
|
||||
if ( false !== $value_index ) {
|
||||
unset( $existing_meta_data[ $meta_data->key ][ $value_index ] );
|
||||
if ( 0 === count( $existing_meta_data[ $meta_data->key ] ) ) {
|
||||
unset( $existing_meta_data[ $meta_data->key ] );
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
add_post_meta( $order->get_id(), $meta_data->key, $meta_data->value, false );
|
||||
}
|
||||
@@ -735,7 +746,11 @@ abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP impleme
|
||||
);
|
||||
|
||||
foreach ( $keys_to_delete as $meta_key ) {
|
||||
delete_post_meta( $order->get_id(), $meta_key );
|
||||
if ( isset( $existing_meta_data[ $meta_key ] ) ) {
|
||||
foreach ( $existing_meta_data[ $meta_key ] as $meta_value ) {
|
||||
delete_post_meta( $order->get_id(), $meta_key, maybe_unserialize( $meta_value ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->update_post_meta( $order );
|
||||
|
||||
+18
-4
@@ -203,7 +203,7 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
||||
$changes = $product->get_changes();
|
||||
|
||||
// Only update the post when the post data changes.
|
||||
if ( array_intersect( array( 'description', 'short_description', 'name', 'parent_id', 'reviews_allowed', 'status', 'menu_order', 'date_created', 'date_modified', 'slug' ), array_keys( $changes ) ) ) {
|
||||
if ( array_intersect( array( 'description', 'short_description', 'name', 'parent_id', 'reviews_allowed', 'status', 'menu_order', 'date_created', 'date_modified', 'slug', 'post_password' ), array_keys( $changes ) ) ) {
|
||||
$post_data = array(
|
||||
'post_content' => $product->get_description( 'edit' ),
|
||||
'post_excerpt' => $product->get_short_description( 'edit' ),
|
||||
@@ -1180,9 +1180,10 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
||||
* @todo Add to interface in 4.0.
|
||||
* @param WC_Product $product Variable product.
|
||||
* @param int $limit Limit the number of created variations.
|
||||
* @param array $default_values Key value pairs to set on created variations.
|
||||
* @return int Number of created variations.
|
||||
*/
|
||||
public function create_all_product_variations( $product, $limit = -1 ) {
|
||||
public function create_all_product_variations( $product, $limit = -1, $default_values = array() ) {
|
||||
$count = 0;
|
||||
|
||||
if ( ! $product ) {
|
||||
@@ -1211,6 +1212,7 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
||||
continue;
|
||||
}
|
||||
$variation = wc_get_product_object( 'variation' );
|
||||
$variation->set_props( $default_values );
|
||||
$variation->set_parent_id( $product->get_id() );
|
||||
$variation->set_attributes( $possible_attribute );
|
||||
$variation_id = $variation->save();
|
||||
@@ -1864,6 +1866,12 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
||||
'field' => 'slug',
|
||||
'terms' => $query_vars['category'],
|
||||
);
|
||||
} elseif ( ! empty( $query_vars['product_category_id'] ) ) {
|
||||
$wp_query_args['tax_query'][] = array(
|
||||
'taxonomy' => 'product_cat',
|
||||
'field' => 'term_id',
|
||||
'terms' => $query_vars['product_category_id'],
|
||||
);
|
||||
}
|
||||
|
||||
// Handle product tags.
|
||||
@@ -1874,6 +1882,12 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
||||
'field' => 'slug',
|
||||
'terms' => $query_vars['tag'],
|
||||
);
|
||||
} elseif ( ! empty( $query_vars['product_tag_id'] ) ) {
|
||||
$wp_query_args['tax_query'][] = array(
|
||||
'taxonomy' => 'product_tag',
|
||||
'field' => 'term_id',
|
||||
'terms' => $query_vars['product_tag_id'],
|
||||
);
|
||||
}
|
||||
|
||||
// Handle shipping classes.
|
||||
@@ -2085,7 +2099,7 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
||||
'onsale' => $sale_price && $price === $sale_price ? 1 : 0,
|
||||
'stock_quantity' => $stock,
|
||||
'stock_status' => get_post_meta( $id, '_stock_status', true ),
|
||||
'rating_count' => array_sum( (array) get_post_meta( $id, '_wc_rating_count', true ) ),
|
||||
'rating_count' => array_sum( array_map( 'intval', (array) get_post_meta( $id, '_wc_rating_count', true ) ) ),
|
||||
'average_rating' => get_post_meta( $id, '_wc_average_rating', true ),
|
||||
'total_sales' => get_post_meta( $id, 'total_sales', true ),
|
||||
'tax_status' => get_post_meta( $id, '_tax_status', true ),
|
||||
@@ -2120,7 +2134,7 @@ class WC_Product_Data_Store_CPT extends WC_Data_Store_WP implements WC_Object_Da
|
||||
global $wpdb;
|
||||
return $wpdb->prepare(
|
||||
"
|
||||
SELECT COALESCE ( MAX( meta_value ), 0 ) FROM $wpdb->postmeta as meta_table
|
||||
SELECT COALESCE( MAX( meta_value ), 0 ) FROM $wpdb->postmeta as meta_table
|
||||
WHERE meta_table.meta_key = '_stock'
|
||||
AND meta_table.post_id = %d
|
||||
",
|
||||
|
||||
@@ -283,6 +283,7 @@ class WC_Webhook_Data_Store implements WC_Webhook_Data_Store_Interface {
|
||||
$date_created = '';
|
||||
$date_modified = '';
|
||||
$user_id = '';
|
||||
$api_version = '';
|
||||
|
||||
if ( ! empty( $args['include'] ) ) {
|
||||
$args['include'] = implode( ',', wp_parse_id_list( $args['include'] ) );
|
||||
@@ -312,6 +313,11 @@ class WC_Webhook_Data_Store implements WC_Webhook_Data_Store_Interface {
|
||||
$date_modified = "AND `date_modified_gmt` BETWEEN STR_TO_DATE('" . esc_sql( $args['modified_after'] ) . "', '%Y-%m-%d %H:%i:%s') and STR_TO_DATE('" . esc_sql( $args['modified_before'] ) . "', '%Y-%m-%d %H:%i:%s')";
|
||||
}
|
||||
|
||||
$api_version_value = $args['api_version'] ?? null;
|
||||
if ( is_numeric( $api_version_value ) ) {
|
||||
$api_version = 'AND `api_version`=' . esc_sql( $api_version_value );
|
||||
}
|
||||
|
||||
// Check for cache.
|
||||
$cache_key = WC_Cache_Helper::get_cache_prefix( 'webhooks' ) . 'search_webhooks' . md5( implode( ',', $args ) );
|
||||
$cache_value = wp_cache_get( $cache_key, 'webhook_search_results' );
|
||||
@@ -331,6 +337,7 @@ class WC_Webhook_Data_Store implements WC_Webhook_Data_Store_Interface {
|
||||
{$exclude}
|
||||
{$date_created}
|
||||
{$date_modified}
|
||||
{$api_version}
|
||||
{$user_id}
|
||||
{$order}
|
||||
{$limit}
|
||||
|
||||
@@ -477,33 +477,13 @@ abstract class WC_CSV_Exporter {
|
||||
}
|
||||
|
||||
/**
|
||||
* Write to the CSV file, ensuring escaping works across versions of
|
||||
* PHP.
|
||||
* Write to the CSV file.
|
||||
*
|
||||
* PHP 5.5.4 uses '\' as the default escape character. This is not RFC-4180 compliant.
|
||||
* \0 disables the escape character.
|
||||
*
|
||||
* @see https://bugs.php.net/bug.php?id=43225
|
||||
* @see https://bugs.php.net/bug.php?id=50686
|
||||
* @see https://github.com/woocommerce/woocommerce/issues/19514
|
||||
* @since 3.4.0
|
||||
* @see https://github.com/woocommerce/woocommerce/issues/24579
|
||||
* @since 3.9.0
|
||||
* @param resource $buffer Resource we are writing to.
|
||||
* @param array $export_row Row to export.
|
||||
*/
|
||||
protected function fputcsv( $buffer, $export_row ) {
|
||||
|
||||
if ( version_compare( PHP_VERSION, '5.5.4', '<' ) ) {
|
||||
ob_start();
|
||||
$temp = fopen( 'php://output', 'w' ); // @codingStandardsIgnoreLine
|
||||
fputcsv( $temp, $export_row, $this->get_delimiter(), '"' ); // @codingStandardsIgnoreLine
|
||||
fclose( $temp ); // @codingStandardsIgnoreLine
|
||||
$row = ob_get_clean();
|
||||
$row = str_replace( '\\"', '\\""', $row );
|
||||
fwrite( $buffer, $row ); // @codingStandardsIgnoreLine
|
||||
} else {
|
||||
fputcsv( $buffer, $export_row, $this->get_delimiter(), '"', "\0" ); // @codingStandardsIgnoreLine
|
||||
}
|
||||
fputcsv( $buffer, $export_row, $this->get_delimiter(), '"', "\0" ); // @codingStandardsIgnoreLine
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +143,12 @@ class WC_Gateway_BACS extends WC_Payment_Gateway {
|
||||
|
||||
?>
|
||||
<tr valign="top">
|
||||
<th scope="row" class="titledesc"><?php esc_html_e( 'Account details:', 'woocommerce' ); ?></th>
|
||||
<th scope="row" class="titledesc">
|
||||
<label>
|
||||
<?php esc_html_e( 'Account details:', 'woocommerce' ); ?>
|
||||
<?php echo wp_kses_post( wc_help_tip( __( 'These account details will be displayed within the order thank you page and confirmation email.', 'woococommerce' ) ) ); ?>
|
||||
</label>
|
||||
</th>
|
||||
<td class="forminp" id="bacs_accounts">
|
||||
<div class="wc_input_table_wrapper">
|
||||
<table class="widefat wc_input_table sortable" cellspacing="0">
|
||||
|
||||
+31
-2
@@ -590,6 +590,35 @@ class WC_Product_CSV_Importer extends WC_Product_Importer {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse dates from a CSV.
|
||||
* Dates can be Unix timestamps or in any format supported by strtotime().
|
||||
*
|
||||
* @param string $value Field value.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function parse_datetime_field( $value ) {
|
||||
try {
|
||||
// If value is a Unix timestamp, convert it to a datetime string.
|
||||
if ( is_numeric( $value ) ) {
|
||||
$datetime = new DateTime( "@{$value}" );
|
||||
// Return datetime string in ISO8601 format (eg. 2018-01-01T00:00:00Z) to preserve UTC timezone since Unix timestamps are always UTC.
|
||||
return $datetime->format( 'Y-m-d\TH:i:s\Z' );
|
||||
}
|
||||
// Check whether the value is a valid date string.
|
||||
if ( false !== strtotime( $value ) ) {
|
||||
// If the value is a valid date string, return as is.
|
||||
return $value;
|
||||
}
|
||||
} catch ( Exception $e ) {
|
||||
// DateTime constructor throws an exception if the value is not a valid Unix timestamp.
|
||||
return null;
|
||||
}
|
||||
// If value is not valid Unix timestamp or date string, return null.
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse backorders from a CSV.
|
||||
*
|
||||
@@ -725,8 +754,8 @@ class WC_Product_CSV_Importer extends WC_Product_Importer {
|
||||
'type' => array( $this, 'parse_comma_field' ),
|
||||
'published' => array( $this, 'parse_published_field' ),
|
||||
'featured' => array( $this, 'parse_bool_field' ),
|
||||
'date_on_sale_from' => array( $this, 'parse_date_field' ),
|
||||
'date_on_sale_to' => array( $this, 'parse_date_field' ),
|
||||
'date_on_sale_from' => array( $this, 'parse_datetime_field' ),
|
||||
'date_on_sale_to' => array( $this, 'parse_datetime_field' ),
|
||||
'name' => array( $this, 'parse_skip_field' ),
|
||||
'short_description' => array( $this, 'parse_description_field' ),
|
||||
'description' => array( $this, 'parse_description_field' ),
|
||||
|
||||
@@ -329,7 +329,7 @@ abstract class WC_Abstract_Legacy_Order extends WC_Data {
|
||||
/**
|
||||
* Set the customer address.
|
||||
* @param array $address Address data.
|
||||
* @param string $type billing or shipping.
|
||||
* @param string $type Type of address; 'billing' or 'shipping'.
|
||||
*/
|
||||
public function set_address( $address, $type = 'billing' ) {
|
||||
foreach ( $address as $key => $value ) {
|
||||
|
||||
@@ -619,22 +619,7 @@ class WC_API_Server {
|
||||
* @return string
|
||||
*/
|
||||
public function get_raw_data() {
|
||||
// @codingStandardsIgnoreStart
|
||||
// $HTTP_RAW_POST_DATA is deprecated on PHP 5.6.
|
||||
if ( function_exists( 'phpversion' ) && version_compare( phpversion(), '5.6', '>=' ) ) {
|
||||
return file_get_contents( 'php://input' );
|
||||
}
|
||||
|
||||
global $HTTP_RAW_POST_DATA;
|
||||
|
||||
// A bug in PHP < 5.2.2 makes $HTTP_RAW_POST_DATA not set by default,
|
||||
// but we can do it ourself.
|
||||
if ( ! isset( $HTTP_RAW_POST_DATA ) ) {
|
||||
$HTTP_RAW_POST_DATA = file_get_contents( 'php://input' );
|
||||
}
|
||||
|
||||
return $HTTP_RAW_POST_DATA;
|
||||
// @codingStandardsIgnoreEnd
|
||||
return file_get_contents( 'php://input' );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -761,7 +761,7 @@ class WC_API_Orders extends WC_API_Resource {
|
||||
*
|
||||
* @param WC_Order $order
|
||||
* @param array $posted
|
||||
* @param string $type
|
||||
* @param string $type Type of address; 'billing' or 'shipping'.
|
||||
*/
|
||||
protected function update_address( $order, $posted, $type = 'billing' ) {
|
||||
foreach ( $posted as $key => $value ) {
|
||||
|
||||
@@ -656,22 +656,7 @@ class WC_API_Server {
|
||||
* @return string
|
||||
*/
|
||||
public function get_raw_data() {
|
||||
// @codingStandardsIgnoreStart
|
||||
// $HTTP_RAW_POST_DATA is deprecated on PHP 5.6.
|
||||
if ( function_exists( 'phpversion' ) && version_compare( phpversion(), '5.6', '>=' ) ) {
|
||||
return file_get_contents( 'php://input' );
|
||||
}
|
||||
|
||||
global $HTTP_RAW_POST_DATA;
|
||||
|
||||
// A bug in PHP < 5.2.2 makes $HTTP_RAW_POST_DATA not set by default,
|
||||
// but we can do it ourself.
|
||||
if ( ! isset( $HTTP_RAW_POST_DATA ) ) {
|
||||
$HTTP_RAW_POST_DATA = file_get_contents( 'php://input' );
|
||||
}
|
||||
|
||||
return $HTTP_RAW_POST_DATA;
|
||||
// @codingStandardsIgnoreEnd
|
||||
return file_get_contents( 'php://input' );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -805,7 +805,7 @@ class WC_API_Orders extends WC_API_Resource {
|
||||
*
|
||||
* @param WC_Order $order
|
||||
* @param array $posted
|
||||
* @param string $type
|
||||
* @param string $type Type of address; 'billing' or 'shipping'.
|
||||
*/
|
||||
protected function update_address( $order, $posted, $type = 'billing' ) {
|
||||
foreach ( $posted as $key => $value ) {
|
||||
|
||||
@@ -658,22 +658,7 @@ class WC_API_Server {
|
||||
* @return string
|
||||
*/
|
||||
public function get_raw_data() {
|
||||
// @codingStandardsIgnoreStart
|
||||
// $HTTP_RAW_POST_DATA is deprecated on PHP 5.6.
|
||||
if ( function_exists( 'phpversion' ) && version_compare( phpversion(), '5.6', '>=' ) ) {
|
||||
return file_get_contents( 'php://input' );
|
||||
}
|
||||
|
||||
global $HTTP_RAW_POST_DATA;
|
||||
|
||||
// A bug in PHP < 5.2.2 makes $HTTP_RAW_POST_DATA not set by default,
|
||||
// but we can do it ourself.
|
||||
if ( ! isset( $HTTP_RAW_POST_DATA ) ) {
|
||||
$HTTP_RAW_POST_DATA = file_get_contents( 'php://input' );
|
||||
}
|
||||
|
||||
return $HTTP_RAW_POST_DATA;
|
||||
// @codingStandardsIgnoreEnd
|
||||
return file_get_contents( 'php://input' );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,6 +9,7 @@ if ( ! function_exists( 'wc_admin_get_feature_config' ) ) {
|
||||
'product-block-editor' => true,
|
||||
'coupons' => true,
|
||||
'core-profiler' => true,
|
||||
'customize-store' => false,
|
||||
'customer-effort-score-tracks' => true,
|
||||
'import-products-task' => true,
|
||||
'experimental-fashion-sample-products' => true,
|
||||
@@ -22,7 +23,9 @@ if ( ! function_exists( 'wc_admin_get_feature_config' ) ) {
|
||||
'new-product-management-experience' => false,
|
||||
'onboarding' => true,
|
||||
'onboarding-tasks' => true,
|
||||
'product-variation-management' => false,
|
||||
'product-variation-management' => true,
|
||||
'product-virtual-downloadable' => false,
|
||||
'product-external-affiliate' => false,
|
||||
'remote-inbox-notifications' => true,
|
||||
'remote-free-extensions' => true,
|
||||
'payment-gateway-suggestions' => true,
|
||||
|
||||
+38
-7
@@ -81,7 +81,22 @@ class WC_REST_Telemetry_Controller extends WC_REST_Controller {
|
||||
}
|
||||
|
||||
$platform = $new['platform'];
|
||||
if ( ! $data[ $platform ] || version_compare( $new['version'], $data[ $platform ]['version'], '>=' ) ) {
|
||||
|
||||
if ( isset( $data[ $platform ] ) ) {
|
||||
$existing_usage = $data[ $platform ];
|
||||
|
||||
// Sets the installation date only if it has not been set before.
|
||||
if ( isset( $new['installation_date'] ) && ! isset( $existing_usage['installation_date'] ) ) {
|
||||
$data[ $platform ]['installation_date'] = $new['installation_date'];
|
||||
}
|
||||
|
||||
if ( version_compare( $new['version'], $existing_usage['version'], '>=' ) ) {
|
||||
$data[ $platform ]['version'] = $new['version'];
|
||||
$data[ $platform ]['last_used'] = $new['last_used'];
|
||||
}
|
||||
} else {
|
||||
// Only sets `first_used` when the platform usage data hasn't been set before.
|
||||
$new['first_used'] = $new['last_used'];
|
||||
$data[ $platform ] = $new;
|
||||
}
|
||||
|
||||
@@ -109,10 +124,19 @@ class WC_REST_Telemetry_Controller extends WC_REST_Controller {
|
||||
return;
|
||||
}
|
||||
|
||||
return array(
|
||||
'platform' => sanitize_text_field( $platform ),
|
||||
'version' => sanitize_text_field( $version ),
|
||||
'last_used' => gmdate( 'c' ),
|
||||
// The installation date could be null from earlier mobile client versions.
|
||||
$installation_date = $request->get_param( 'installation_date' );
|
||||
|
||||
return array_filter(
|
||||
array(
|
||||
'platform' => sanitize_text_field( $platform ),
|
||||
'version' => sanitize_text_field( $version ),
|
||||
'last_used' => gmdate( 'c' ),
|
||||
'installation_date' => isset( $installation_date ) ? get_gmt_from_date( $installation_date, 'c' ) : null,
|
||||
),
|
||||
function( $value ) {
|
||||
return null !== $value;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@@ -123,20 +147,27 @@ class WC_REST_Telemetry_Controller extends WC_REST_Controller {
|
||||
*/
|
||||
public function get_collection_params() {
|
||||
return array(
|
||||
'platform' => array(
|
||||
'platform' => array(
|
||||
'description' => __( 'Platform to track.', 'woocommerce' ),
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
),
|
||||
'version' => array(
|
||||
'version' => array(
|
||||
'description' => __( 'Platform version to track.', 'woocommerce' ),
|
||||
'required' => true,
|
||||
'type' => 'string',
|
||||
'sanitize_callback' => 'sanitize_text_field',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
),
|
||||
'installation_date' => array(
|
||||
'description' => __( 'Installation date of the WooCommerce mobile app.', 'woocommerce' ),
|
||||
'required' => false, // For backward compatibility.
|
||||
'type' => 'string',
|
||||
'format' => 'date-time',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -593,9 +593,9 @@ class WC_REST_Orders_V1_Controller extends WC_REST_Posts_Controller {
|
||||
/**
|
||||
* Update address.
|
||||
*
|
||||
* @param WC_Order $order
|
||||
* @param array $posted
|
||||
* @param string $type
|
||||
* @param WC_Order $order Order object.
|
||||
* @param array $posted Request data.
|
||||
* @param string $type Type of address; 'billing' or 'shipping'.
|
||||
*/
|
||||
protected function update_address( $order, $posted, $type = 'billing' ) {
|
||||
foreach ( $posted as $key => $value ) {
|
||||
|
||||
+1
-1
@@ -804,7 +804,7 @@ class WC_REST_Orders_V2_Controller extends WC_REST_CRUD_Controller {
|
||||
*
|
||||
* @param WC_Order $order Order data.
|
||||
* @param array $posted Posted data.
|
||||
* @param string $type Address type.
|
||||
* @param string $type Type of address; 'billing' or 'shipping'.
|
||||
*/
|
||||
protected function update_address( $order, $posted, $type = 'billing' ) {
|
||||
foreach ( $posted as $key => $value ) {
|
||||
|
||||
+7
-2
@@ -1333,12 +1333,12 @@ class WC_REST_System_Status_V2_Controller extends WC_REST_Controller {
|
||||
),
|
||||
_x( 'Cart', 'Page setting', 'woocommerce' ) => array(
|
||||
'option' => 'woocommerce_cart_page_id',
|
||||
'shortcode' => '[' . apply_filters( 'woocommerce_cart_shortcode_tag', 'woocommerce_cart' ) . ']',
|
||||
'shortcode' => '[' . apply_filters_deprecated( 'woocommerce_cart_shortcode_tag', array( 'woocommerce_cart' ), '8.3.0', 'woocommerce_create_pages' ) . ']',
|
||||
'block' => 'woocommerce/cart',
|
||||
),
|
||||
_x( 'Checkout', 'Page setting', 'woocommerce' ) => array(
|
||||
'option' => 'woocommerce_checkout_page_id',
|
||||
'shortcode' => '[' . apply_filters( 'woocommerce_checkout_shortcode_tag', 'woocommerce_checkout' ) . ']',
|
||||
'shortcode' => '[' . apply_filters_deprecated( 'woocommerce_checkout_shortcode_tag', array( 'woocommerce_checkout' ), '8.3.0', 'woocommerce_create_pages' ) . ']',
|
||||
'block' => 'woocommerce/checkout',
|
||||
),
|
||||
_x( 'My account', 'Page setting', 'woocommerce' ) => array(
|
||||
@@ -1388,6 +1388,11 @@ class WC_REST_System_Status_V2_Controller extends WC_REST_Controller {
|
||||
if ( $values['block'] && get_post( $page_id ) ) {
|
||||
$block_required = true;
|
||||
$block_present = WC_Blocks_Utils::has_block_in_page( $page_id, $values['block'] );
|
||||
|
||||
// Compatibility with the classic shortcode block which can be used instead of shortcodes.
|
||||
if ( ! $block_present && ( 'woocommerce/checkout' === $values['block'] || 'woocommerce/cart' === $values['block'] ) ) {
|
||||
$block_present = WC_Blocks_Utils::has_block_in_page( $page_id, 'woocommerce/classic-shortcode', true );
|
||||
}
|
||||
}
|
||||
|
||||
// Wrap up our findings into an output array.
|
||||
|
||||
+84
@@ -24,4 +24,88 @@ class WC_REST_Product_Attributes_Controller extends WC_REST_Product_Attributes_V
|
||||
* @var string
|
||||
*/
|
||||
protected $namespace = 'wc/v3';
|
||||
|
||||
/**
|
||||
* Generates a unique slug for a given attribute name. We do this so that we can
|
||||
* create more than one attribute with the same name.
|
||||
*
|
||||
* @param string $attribute_name The attribute name to generate a slug for.
|
||||
* @return string The auto-generated slug
|
||||
*/
|
||||
private function generate_unique_slug( $attribute_name ) {
|
||||
global $wpdb;
|
||||
|
||||
$root_slug = wc_sanitize_taxonomy_name( $attribute_name );
|
||||
|
||||
$results = $wpdb->get_results(
|
||||
$wpdb->prepare( "SELECT attribute_name FROM {$wpdb->prefix}woocommerce_attribute_taxonomies WHERE attribute_name LIKE %s ORDER BY attribute_id DESC LIMIT 1", $root_slug . '%' )
|
||||
);
|
||||
|
||||
// The slug is already unique!
|
||||
if ( empty( $results ) ) {
|
||||
return $root_slug;
|
||||
}
|
||||
|
||||
$last_created_slug = $results[0]->attribute_name;
|
||||
$suffix = intval( substr( $last_created_slug, strrpos( $last_created_slug, '-' ) + 1 ) );
|
||||
|
||||
return $root_slug . '-' . ( $suffix + 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a single attribute.
|
||||
*
|
||||
* @param WP_REST_Request $request Full details about the request.
|
||||
* @return WP_REST_Request|WP_Error
|
||||
*/
|
||||
public function create_item( $request ) {
|
||||
global $wpdb;
|
||||
|
||||
$generate_slug = stripslashes( $request['generate_slug'] );
|
||||
$slug = wc_sanitize_taxonomy_name( stripslashes( $request['slug'] ) );
|
||||
|
||||
if ( ! empty( $generate_slug ) && 'true' === $generate_slug ) {
|
||||
$slug = $this->generate_unique_slug( $request['name'] );
|
||||
}
|
||||
|
||||
$id = wc_create_attribute(
|
||||
array(
|
||||
'name' => $request['name'],
|
||||
'slug' => $slug,
|
||||
'type' => ! empty( $request['type'] ) ? $request['type'] : 'select',
|
||||
'order_by' => ! empty( $request['order_by'] ) ? $request['order_by'] : 'menu_order',
|
||||
'has_archives' => true === $request['has_archives'],
|
||||
)
|
||||
);
|
||||
|
||||
// Checks for errors.
|
||||
if ( is_wp_error( $id ) ) {
|
||||
return new WP_Error( 'woocommerce_rest_cannot_create', $id->get_error_message(), array( 'status' => 400 ) );
|
||||
}
|
||||
|
||||
$attribute = $this->get_attribute( $id );
|
||||
|
||||
if ( is_wp_error( $attribute ) ) {
|
||||
return $attribute;
|
||||
}
|
||||
|
||||
$this->update_additional_fields_for_object( $attribute, $request );
|
||||
|
||||
/**
|
||||
* Fires after a single product attribute is created or updated via the REST API.
|
||||
*
|
||||
* @param stdObject $attribute Inserted attribute object.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
* @param boolean $creating True when creating attribute, false when updating.
|
||||
*/
|
||||
do_action( 'woocommerce_rest_insert_product_attribute', $attribute, $request, true );
|
||||
|
||||
$request->set_param( 'context', 'edit' );
|
||||
$response = $this->prepare_item_for_response( $attribute, $request );
|
||||
$response = rest_ensure_response( $response );
|
||||
$response->set_status( 201 );
|
||||
$response->header( 'Location', rest_url( '/' . $this->namespace . '/' . $this->rest_base . '/' . $attribute->attribute_id ) );
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
+149
-5
@@ -40,10 +40,19 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Product_Variations_V
|
||||
'/' . $this->rest_base . '/generate',
|
||||
array(
|
||||
'args' => array(
|
||||
'product_id' => array(
|
||||
'product_id' => array(
|
||||
'description' => __( 'Unique identifier for the variable product.', 'woocommerce' ),
|
||||
'type' => 'integer',
|
||||
),
|
||||
'delete' => array(
|
||||
'description' => __( 'Deletes unused variations.', 'woocommerce' ),
|
||||
'type' => 'boolean',
|
||||
),
|
||||
'default_values' => array(
|
||||
'description' => __( 'Default values for generated variations.', 'woocommerce' ),
|
||||
'type' => 'object',
|
||||
'properties' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
|
||||
),
|
||||
),
|
||||
array(
|
||||
'methods' => WP_REST_Server::CREATABLE,
|
||||
@@ -90,7 +99,7 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Product_Variations_V
|
||||
'download_limit' => '' !== $object->get_download_limit() ? (int) $object->get_download_limit() : -1,
|
||||
'download_expiry' => '' !== $object->get_download_expiry() ? (int) $object->get_download_expiry() : -1,
|
||||
'tax_status' => $object->get_tax_status(),
|
||||
'tax_class' => $object->get_tax_class(),
|
||||
'tax_class' => $object->get_tax_class( $context ),
|
||||
'manage_stock' => $object->managing_stock(),
|
||||
'stock_quantity' => $object->get_stock_quantity(),
|
||||
'stock_status' => $object->get_stock_status(),
|
||||
@@ -110,6 +119,8 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Product_Variations_V
|
||||
'attributes' => $this->get_attributes( $object ),
|
||||
'menu_order' => $object->get_menu_order(),
|
||||
'meta_data' => $object->get_meta_data(),
|
||||
'name' => wc_get_formatted_variation( $object, true, false, false ),
|
||||
'parent_id' => $object->get_parent_id(),
|
||||
);
|
||||
|
||||
$data = $this->add_additional_fields_to_object( $data, $request );
|
||||
@@ -123,6 +134,7 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Product_Variations_V
|
||||
* The dynamic portion of the hook name, $this->post_type,
|
||||
* refers to object type being prepared for the response.
|
||||
*
|
||||
* @since 4.5.0
|
||||
* @param WP_REST_Response $response The response object.
|
||||
* @param WC_Data $object Object data.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
@@ -341,6 +353,7 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Product_Variations_V
|
||||
* The dynamic portion of the hook name, `$this->post_type`,
|
||||
* refers to the object type slug.
|
||||
*
|
||||
* @since 4.5.0
|
||||
* @param WC_Data $variation Object object.
|
||||
* @param WP_REST_Request $request Request object.
|
||||
* @param bool $creating If is creating a new object.
|
||||
@@ -401,6 +414,15 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Product_Variations_V
|
||||
$upload = wc_rest_upload_image_from_url( esc_url_raw( $image['src'] ) );
|
||||
|
||||
if ( is_wp_error( $upload ) ) {
|
||||
/**
|
||||
* Filter to check if it should supress the image upload error, false by default.
|
||||
*
|
||||
* @since 4.5.0
|
||||
* @param bool false If it should suppress.
|
||||
* @param array $upload Uploaded image array.
|
||||
* @param int id Variation id.
|
||||
* @param array Array of image to set.
|
||||
*/
|
||||
if ( ! apply_filters( 'woocommerce_rest_suppress_image_upload_error', false, $upload, $variation->get_id(), array( $image ) ) ) {
|
||||
throw new WC_REST_Exception( 'woocommerce_variation_image_upload_error', $upload->get_error_message(), 400 );
|
||||
}
|
||||
@@ -639,7 +661,7 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Product_Variations_V
|
||||
'context' => array( 'view', 'edit' ),
|
||||
'readonly' => true,
|
||||
),
|
||||
'low_stock_amount' => array(
|
||||
'low_stock_amount' => array(
|
||||
'description' => __( 'Low Stock amount for the variation.', 'woocommerce' ),
|
||||
'type' => array( 'integer', 'null' ),
|
||||
'context' => array( 'view', 'edit' ),
|
||||
@@ -812,8 +834,12 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Product_Variations_V
|
||||
// Set post_status.
|
||||
$args['post_status'] = $request['status'];
|
||||
|
||||
// Filter by local attributes.
|
||||
/**
|
||||
* @deprecated 8.1.0 replaced by attributes.
|
||||
* Filter by local attributes.
|
||||
*/
|
||||
if ( ! empty( $request['local_attributes'] ) && is_array( $request['local_attributes'] ) ) {
|
||||
wc_deprecated_argument( 'local_attributes', '8.1', 'Use "attributes" instead.' );
|
||||
foreach ( $request['local_attributes'] as $attribute ) {
|
||||
if ( ! isset( $attribute['attribute'] ) || ! isset( $attribute['term'] ) ) {
|
||||
continue;
|
||||
@@ -828,6 +854,22 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Product_Variations_V
|
||||
}
|
||||
}
|
||||
|
||||
// Filter by attributes.
|
||||
if ( ! empty( $request['attributes'] ) && is_array( $request['attributes'] ) ) {
|
||||
foreach ( $request['attributes'] as $attribute ) {
|
||||
if ( ! isset( $attribute['attribute'] ) || ! isset( $attribute['term'] ) ) {
|
||||
continue;
|
||||
}
|
||||
$args['meta_query'] = $this->add_meta_query( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
|
||||
$args,
|
||||
array(
|
||||
'key' => 'attribute_' . $attribute['attribute'],
|
||||
'value' => $attribute['term'],
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Filter by sku.
|
||||
if ( ! empty( $request['sku'] ) ) {
|
||||
$skus = explode( ',', $request['sku'] );
|
||||
@@ -862,6 +904,43 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Product_Variations_V
|
||||
$args['meta_query'] = $this->add_meta_query( $args, wc_get_min_max_price_meta_query( $request ) ); // WPCS: slow query ok.
|
||||
}
|
||||
|
||||
// Price filter.
|
||||
if ( is_bool( $request['has_price'] ) ) {
|
||||
if ( $request['has_price'] ) {
|
||||
$args['meta_query'] = $this->add_meta_query( // phpcs:ignore Standard.Category.SniffName.ErrorCode slow query ok.
|
||||
$args,
|
||||
array(
|
||||
'relation' => 'AND',
|
||||
array(
|
||||
'key' => '_price',
|
||||
'compare' => 'EXISTS',
|
||||
),
|
||||
array(
|
||||
'key' => '_price',
|
||||
'compare' => '!=',
|
||||
'value' => null,
|
||||
),
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$args['meta_query'] = $this->add_meta_query( // phpcs:ignore Standard.Category.SniffName.ErrorCode slow query ok.
|
||||
$args,
|
||||
array(
|
||||
'relation' => 'OR',
|
||||
array(
|
||||
'key' => '_price',
|
||||
'compare' => 'NOT EXISTS',
|
||||
),
|
||||
array(
|
||||
'key' => '_price',
|
||||
'compare' => '=',
|
||||
'value' => null,
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Filter product based on stock_status.
|
||||
if ( ! empty( $request['stock_status'] ) ) {
|
||||
$args['meta_query'] = $this->add_meta_query( // WPCS: slow query ok.
|
||||
@@ -923,9 +1002,68 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Product_Variations_V
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
);
|
||||
|
||||
$params['has_price'] = array(
|
||||
'description' => __( 'Limit result set to products with or without price.', 'woocommerce' ),
|
||||
'type' => 'boolean',
|
||||
'sanitize_callback' => 'wc_string_to_bool',
|
||||
'validate_callback' => 'rest_validate_request_arg',
|
||||
);
|
||||
|
||||
$params['attributes'] = array(
|
||||
'description' => __( 'Limit result set to products with specified attributes.', 'woocommerce' ),
|
||||
'type' => 'array',
|
||||
'items' => array(
|
||||
'type' => 'object',
|
||||
'properties' => array(
|
||||
'attribute' => array(
|
||||
'type' => 'string',
|
||||
'description' => __( 'Attribute slug.', 'woocommerce' ),
|
||||
),
|
||||
'term' => array(
|
||||
'type' => 'string',
|
||||
'description' => __( 'Attribute term.', 'woocommerce' ),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all unmatched variations (aka duplicates).
|
||||
*
|
||||
* @param WC_Product $product Variable product.
|
||||
* @return int Number of deleted variations.
|
||||
*/
|
||||
private function delete_unmatched_product_variations( $product ) {
|
||||
$deleted_count = 0;
|
||||
|
||||
if ( ! $product ) {
|
||||
return $deleted_count;
|
||||
}
|
||||
|
||||
$attributes = wc_list_pluck( array_filter( $product->get_attributes(), 'wc_attributes_array_filter_variation' ), 'get_slugs' );
|
||||
|
||||
// Get existing variations so we don't create duplicates.
|
||||
$existing_variations = array_map( 'wc_get_product', $product->get_children() );
|
||||
|
||||
$possible_attribute_combinations = array_reverse( wc_array_cartesian( $attributes ) );
|
||||
|
||||
foreach ( $existing_variations as $existing_variation ) {
|
||||
$matching_attribute_key = array_search( $existing_variation->get_attributes(), $possible_attribute_combinations ); // phpcs:ignore WordPress.PHP.StrictInArray.MissingTrueStrict
|
||||
if ( false !== $matching_attribute_key ) {
|
||||
// We only want one possible variation for each possible attribute combination.
|
||||
unset( $possible_attribute_combinations[ $matching_attribute_key ] );
|
||||
continue;
|
||||
}
|
||||
$existing_variation->delete( true );
|
||||
$deleted_count ++;
|
||||
}
|
||||
|
||||
return $deleted_count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate all variations for a given product.
|
||||
*
|
||||
@@ -944,8 +1082,14 @@ class WC_REST_Product_Variations_Controller extends WC_REST_Product_Variations_V
|
||||
|
||||
$response = array();
|
||||
$product = wc_get_product( $product_id );
|
||||
$default_values = isset( $request['default_values'] ) ? $request['default_values'] : array();
|
||||
$data_store = $product->get_data_store();
|
||||
$response['count'] = $data_store->create_all_product_variations( $product, Constants::get_constant( 'WC_MAX_LINKED_VARIATIONS' ) );
|
||||
$response['count'] = $data_store->create_all_product_variations( $product, Constants::get_constant( 'WC_MAX_LINKED_VARIATIONS' ), $default_values );
|
||||
|
||||
if ( isset( $request['delete'] ) && $request['delete'] ) {
|
||||
$deleted_count = $this->delete_unmatched_product_variations( $product );
|
||||
$response['deleted_count'] = $deleted_count;
|
||||
}
|
||||
|
||||
$data_store->sort_all_product_variations( $product->get_id() );
|
||||
|
||||
|
||||
+14
@@ -432,6 +432,11 @@ class WC_REST_Products_Controller extends WC_REST_Products_V2_Controller {
|
||||
$product->set_reviews_allowed( $request['reviews_allowed'] );
|
||||
}
|
||||
|
||||
// Post password.
|
||||
if ( isset( $request['post_password'] ) ) {
|
||||
$product->set_post_password( $request['post_password'] );
|
||||
}
|
||||
|
||||
// Virtual.
|
||||
if ( isset( $request['virtual'] ) ) {
|
||||
$product->set_virtual( $request['virtual'] );
|
||||
@@ -1140,6 +1145,11 @@ class WC_REST_Products_Controller extends WC_REST_Products_V2_Controller {
|
||||
'default' => true,
|
||||
'context' => array( 'view', 'edit' ),
|
||||
),
|
||||
'post_password' => array(
|
||||
'description' => __( 'Post password.', 'woocommerce' ),
|
||||
'type' => 'string',
|
||||
'context' => array( 'view', 'edit' ),
|
||||
),
|
||||
'average_rating' => array(
|
||||
'description' => __( 'Reviews average rating.', 'woocommerce' ),
|
||||
'type' => 'string',
|
||||
@@ -1496,6 +1506,10 @@ class WC_REST_Products_Controller extends WC_REST_Products_V2_Controller {
|
||||
$data['has_options'] = $product->has_options( $context );
|
||||
}
|
||||
|
||||
if ( in_array( 'post_password', $fields, true ) ) {
|
||||
$data['post_password'] = $product->get_post_password( $context );
|
||||
}
|
||||
|
||||
$post_type_obj = get_post_type_object( $this->post_type );
|
||||
if ( is_post_type_viewable( $post_type_obj ) && $post_type_obj->public ) {
|
||||
$permalink_template_requested = in_array( 'permalink_template', $fields, true );
|
||||
|
||||
+3
-4
@@ -162,12 +162,11 @@ class WC_Shipping_Free_Shipping extends WC_Shipping_Method {
|
||||
if ( in_array( $this->requires, array( 'min_amount', 'either', 'both' ), true ) ) {
|
||||
$total = WC()->cart->get_displayed_subtotal();
|
||||
|
||||
if ( WC()->cart->display_prices_including_tax() ) {
|
||||
$total = $total - WC()->cart->get_discount_tax();
|
||||
}
|
||||
|
||||
if ( 'no' === $this->ignore_discounts ) {
|
||||
$total = $total - WC()->cart->get_discount_total();
|
||||
if ( WC()->cart->display_prices_including_tax() ) {
|
||||
$total = $total - WC()->cart->get_discount_tax();
|
||||
}
|
||||
}
|
||||
|
||||
$total = NumberUtil::round( $total, wc_get_price_decimals() );
|
||||
|
||||
+7
-9
@@ -271,7 +271,7 @@ class WC_Shortcode_Checkout {
|
||||
if ( $order_id > 0 ) {
|
||||
$order = wc_get_order( $order_id );
|
||||
|
||||
if ( ! $order || ! hash_equals( $order->get_order_key(), $order_key ) ) {
|
||||
if ( ( ! $order instanceof WC_Order ) || ! hash_equals( $order->get_order_key(), $order_key ) ) {
|
||||
$order = false;
|
||||
}
|
||||
}
|
||||
@@ -301,6 +301,7 @@ class WC_Shortcode_Checkout {
|
||||
|
||||
// For non-guest orders, require the user to be logged in before showing this page.
|
||||
if ( $order_customer_id && get_current_user_id() !== $order_customer_id ) {
|
||||
wc_get_template( 'checkout/order-received.php', array( 'order' => false ) );
|
||||
wc_print_notice( esc_html__( 'Please log in to your account to view this order.', 'woocommerce' ), 'notice' );
|
||||
woocommerce_login_form( array( 'redirect' => $order->get_checkout_order_received_url() ) );
|
||||
return;
|
||||
@@ -308,6 +309,7 @@ class WC_Shortcode_Checkout {
|
||||
|
||||
// For guest orders, request they verify their email address (unless we can identify them via the active user session).
|
||||
if ( self::guest_should_verify_email( $order, 'order-received' ) ) {
|
||||
wc_get_template( 'checkout/order-received.php', array( 'order' => false ) );
|
||||
wc_get_template(
|
||||
'checkout/form-verify-email.php',
|
||||
array(
|
||||
@@ -385,11 +387,6 @@ class WC_Shortcode_Checkout {
|
||||
return false;
|
||||
}
|
||||
|
||||
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
||||
if ( ! empty( $_POST ) && ! wp_verify_nonce( $_POST['check_submission'] ?? '', 'wc_verify_email' ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Controls the grace period within which we do not require any sort of email verification step before rendering
|
||||
* the 'order received' or 'order pay' pages.
|
||||
@@ -423,11 +420,12 @@ class WC_Shortcode_Checkout {
|
||||
$session_email = is_array( $customer ) && isset( $customer['email'] ) ? $customer['email'] : '';
|
||||
}
|
||||
|
||||
$session_email_match = $session_email === $order->get_billing_email();
|
||||
$supplied_email_match = isset( $_POST['email'] ) && sanitize_email( wp_unslash( $_POST['email'] ) ?? '' ) === $order->get_billing_email();
|
||||
// Email verification is required if the user cannot be identified, or if they supplied an email address but the nonce check failed.
|
||||
$can_view_orders = current_user_can( 'read_private_shop_orders' );
|
||||
$session_email_match = $session_email === $order->get_billing_email();
|
||||
$supplied_email_match = sanitize_email( wp_unslash( filter_input( INPUT_POST, 'email' ) ) ) === $order->get_billing_email()
|
||||
&& wp_verify_nonce( filter_input( INPUT_POST, 'check_submission' ), 'wc_verify_email' );
|
||||
|
||||
// If we cannot match the order with the current user, the user should verify their email address.
|
||||
$email_verification_required = ! $session_email_match && ! $supplied_email_match && ! $can_view_orders;
|
||||
|
||||
/**
|
||||
|
||||
+1
-1
@@ -165,7 +165,7 @@ class WC_Shortcode_My_Account {
|
||||
/**
|
||||
* Edit address page.
|
||||
*
|
||||
* @param string $load_address Type of address to load.
|
||||
* @param string $load_address Type of address; 'billing' or 'shipping'.
|
||||
*/
|
||||
public static function edit_address( $load_address = 'billing' ) {
|
||||
$current_user = wp_get_current_user();
|
||||
|
||||
@@ -55,7 +55,7 @@ class WC_Tracks_Event {
|
||||
* @return bool Always returns true.
|
||||
*/
|
||||
public function record() {
|
||||
if ( wp_doing_ajax() || Constants::is_true( 'REST_REQUEST' ) ) {
|
||||
if ( wp_doing_ajax() || Constants::is_true( 'REST_REQUEST' ) || Constants::is_true( 'WP_CLI' ) || wp_doing_cron() ) {
|
||||
return WC_Tracks_Client::record_event( $this );
|
||||
}
|
||||
|
||||
|
||||
@@ -309,11 +309,9 @@ function wc_get_account_orders_actions( $order ) {
|
||||
* Get account formatted address.
|
||||
*
|
||||
* @since 3.2.0
|
||||
* @param string $address_type Address type.
|
||||
* Accepts: 'billing' or 'shipping'.
|
||||
* Default to 'billing'.
|
||||
* @param string $address_type Type of address; 'billing' or 'shipping'.
|
||||
* @param int $customer_id Customer ID.
|
||||
* Default to 0.
|
||||
* Defaults to 0.
|
||||
* @return string
|
||||
*/
|
||||
function wc_get_account_formatted_address( $address_type = 'billing', $customer_id = 0 ) {
|
||||
|
||||
@@ -176,7 +176,7 @@ function wc_clear_cart_after_payment() {
|
||||
if ( $order_id > 0 ) {
|
||||
$order = wc_get_order( $order_id );
|
||||
|
||||
if ( $order && hash_equals( $order->get_order_key(), $order_key ) ) {
|
||||
if ( $order instanceof WC_Order && hash_equals( $order->get_order_key(), $order_key ) ) {
|
||||
WC()->cart->empty_cart();
|
||||
}
|
||||
}
|
||||
@@ -185,7 +185,7 @@ function wc_clear_cart_after_payment() {
|
||||
if ( WC()->session->order_awaiting_payment > 0 ) {
|
||||
$order = wc_get_order( WC()->session->order_awaiting_payment );
|
||||
|
||||
if ( $order && $order->get_id() > 0 ) {
|
||||
if ( $order instanceof WC_Order && $order->get_id() > 0 ) {
|
||||
// If the order has not failed, or is not pending, the order must have gone through.
|
||||
if ( ! $order->has_status( array( 'failed', 'pending', 'cancelled' ) ) ) {
|
||||
WC()->cart->empty_cart();
|
||||
|
||||
@@ -102,7 +102,7 @@ if ( ! function_exists( 'is_cart' ) ) {
|
||||
if ( ! function_exists( 'is_checkout' ) ) {
|
||||
|
||||
/**
|
||||
* Is_checkout - Returns true when viewing the checkout page.
|
||||
* Is_checkout - Returns true when viewing the checkout page, or when processing AJAX requests for updating or processing the checkout.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
|
||||
@@ -631,8 +631,8 @@ function get_woocommerce_currencies() {
|
||||
'USD' => __( 'United States (US) dollar', 'woocommerce' ),
|
||||
'UYU' => __( 'Uruguayan peso', 'woocommerce' ),
|
||||
'UZS' => __( 'Uzbekistani som', 'woocommerce' ),
|
||||
'VEF' => __( 'Venezuelan bolívar', 'woocommerce' ),
|
||||
'VES' => __( 'Bolívar soberano', 'woocommerce' ),
|
||||
'VEF' => __( 'Venezuelan bolívar (2008–2018)', 'woocommerce' ),
|
||||
'VES' => __( 'Venezuelan bolívar', 'woocommerce' ),
|
||||
'VND' => __( 'Vietnamese đồng', 'woocommerce' ),
|
||||
'VUV' => __( 'Vanuatu vatu', 'woocommerce' ),
|
||||
'WST' => __( 'Samoan tālā', 'woocommerce' ),
|
||||
@@ -817,7 +817,7 @@ function get_woocommerce_currency_symbols() {
|
||||
'UYU' => '$',
|
||||
'UZS' => 'UZS',
|
||||
'VEF' => 'Bs F',
|
||||
'VES' => 'Bs.S',
|
||||
'VES' => 'Bs.',
|
||||
'VND' => '₫',
|
||||
'VUV' => 'Vt',
|
||||
'WST' => 'T',
|
||||
@@ -1094,11 +1094,7 @@ function wc_setcookie( $name, $value, $expire = 0, $secure = false, $httponly =
|
||||
$value
|
||||
);
|
||||
|
||||
if ( version_compare( PHP_VERSION, '7.3.0', '>=' ) ) {
|
||||
setcookie( $name, $value, $options );
|
||||
} else {
|
||||
setcookie( $name, $value, $options['expires'], $options['path'], $options['domain'], $options['secure'], $options['httponly'] );
|
||||
}
|
||||
setcookie( $name, $value, $options );
|
||||
} elseif ( Constants::is_true( 'WP_DEBUG' ) ) {
|
||||
headers_sent( $file, $line );
|
||||
trigger_error( "{$name} cookie cannot be set - headers already sent by {$file} on line {$line}", E_USER_NOTICE ); // @codingStandardsIgnoreLine
|
||||
@@ -2507,15 +2503,7 @@ function wc_decimal_to_fraction( $decimal ) {
|
||||
* @return float
|
||||
*/
|
||||
function wc_round_discount( $value, $precision ) {
|
||||
if ( version_compare( PHP_VERSION, '5.3.0', '>=' ) ) {
|
||||
return NumberUtil::round( $value, $precision, WC_DISCOUNT_ROUNDING_MODE ); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctionParameters.round_modeFound
|
||||
}
|
||||
|
||||
if ( PHP_ROUND_HALF_DOWN === WC_DISCOUNT_ROUNDING_MODE ) {
|
||||
return wc_legacy_round_half_down( $value, $precision );
|
||||
}
|
||||
|
||||
return NumberUtil::round( $value, $precision );
|
||||
return NumberUtil::round( $value, $precision, WC_DISCOUNT_ROUNDING_MODE ); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctionParameters.round_modeFound
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2544,7 +2532,7 @@ function wc_selected( $value, $options ) {
|
||||
function wc_get_server_database_version() {
|
||||
global $wpdb;
|
||||
|
||||
if ( empty( $wpdb->is_mysql ) || ! $wpdb->use_mysqli ) {
|
||||
if ( empty( $wpdb->is_mysql ) || empty( $wpdb->use_mysqli ) ) {
|
||||
return array(
|
||||
'string' => '',
|
||||
'number' => '',
|
||||
|
||||
@@ -233,14 +233,7 @@ function wc_trim_zeros( $price ) {
|
||||
*/
|
||||
function wc_round_tax_total( $value, $precision = null ) {
|
||||
$precision = is_null( $precision ) ? wc_get_price_decimals() : intval( $precision );
|
||||
|
||||
if ( version_compare( PHP_VERSION, '5.3.0', '>=' ) ) {
|
||||
$rounded_tax = NumberUtil::round( $value, $precision, wc_get_tax_rounding_mode() ); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctionParameters.round_modeFound
|
||||
} elseif ( 2 === wc_get_tax_rounding_mode() ) {
|
||||
$rounded_tax = wc_legacy_round_half_down( $value, $precision );
|
||||
} else {
|
||||
$rounded_tax = NumberUtil::round( $value, $precision );
|
||||
}
|
||||
$rounded_tax = NumberUtil::round( $value, $precision, wc_get_tax_rounding_mode() ); // phpcs:ignore PHPCompatibility.FunctionUse.NewFunctionParameters.round_modeFound
|
||||
|
||||
return apply_filters( 'wc_round_tax_total', $rounded_tax, $value, $precision, WC_TAX_ROUNDING_MODE );
|
||||
}
|
||||
|
||||
@@ -448,7 +448,6 @@ function wc_scheduled_sales() {
|
||||
|
||||
if ( $sale_price ) {
|
||||
$product->set_price( $sale_price );
|
||||
$product->set_date_on_sale_from( '' );
|
||||
} else {
|
||||
$product->set_date_on_sale_to( '' );
|
||||
$product->set_date_on_sale_from( '' );
|
||||
|
||||
@@ -2338,7 +2338,7 @@ if ( ! function_exists( 'woocommerce_breadcrumb' ) ) {
|
||||
'woocommerce_breadcrumb_defaults',
|
||||
array(
|
||||
'delimiter' => ' / ',
|
||||
'wrap_before' => '<nav class="woocommerce-breadcrumb">',
|
||||
'wrap_before' => '<nav class="woocommerce-breadcrumb" aria-label="Breadcrumb">',
|
||||
'wrap_after' => '</nav>',
|
||||
'before' => '',
|
||||
'after' => '',
|
||||
@@ -3295,7 +3295,7 @@ if ( ! function_exists( 'woocommerce_account_edit_address' ) ) {
|
||||
/**
|
||||
* My Account > Edit address template.
|
||||
*
|
||||
* @param string $type Address type.
|
||||
* @param string $type Type of address; 'billing' or 'shipping'.
|
||||
*/
|
||||
function woocommerce_account_edit_address( $type ) {
|
||||
$type = wc_edit_address_i18n( sanitize_title( $type ), true );
|
||||
|
||||
@@ -21,6 +21,7 @@ defined( 'ABSPATH' ) || exit;
|
||||
use Automattic\WooCommerce\Database\Migrations\MigrationHelper;
|
||||
use Automattic\WooCommerce\Internal\Admin\Marketing\MarketingSpecs;
|
||||
use Automattic\WooCommerce\Internal\AssignDefaultCategory;
|
||||
use Automattic\WooCommerce\Internal\DataStores\Orders\DataSynchronizer;
|
||||
use Automattic\WooCommerce\Internal\DataStores\Orders\OrdersTableDataStore;
|
||||
use Automattic\WooCommerce\Internal\ProductAttributesLookup\DataRegenerator;
|
||||
use Automattic\WooCommerce\Internal\ProductAttributesLookup\LookupDataStore;
|
||||
@@ -2591,3 +2592,50 @@ function wc_update_770_remove_multichannel_marketing_feature_options() {
|
||||
delete_option( 'woocommerce_multichannel_marketing_enabled' );
|
||||
delete_option( 'woocommerce_marketing_overview_welcome_hidden' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate transaction data which was being incorrectly stored in the postmeta table to HPOS tables.
|
||||
*
|
||||
* @return bool Whether there are pending migration recrods.
|
||||
*/
|
||||
function wc_update_810_migrate_transactional_metadata_for_hpos() {
|
||||
global $wpdb;
|
||||
|
||||
$data_synchronizer = wc_get_container()->get( DataSynchronizer::class );
|
||||
if ( ! $data_synchronizer->get_table_exists() ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$orders_table = OrdersTableDataStore::get_orders_table_name();
|
||||
$orders_meta_table = OrdersTableDataStore::get_meta_table_name();
|
||||
|
||||
/**
|
||||
* We are migrating payment_tokens meta that is stored in wp_postmeta table to the HPOS table. To do this with minimum db ops:
|
||||
* 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.
|
||||
* 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.
|
||||
*/
|
||||
$select_query = "
|
||||
SELECT post_id, '_payment_tokens', {$wpdb->postmeta}.meta_value
|
||||
FROM {$wpdb->postmeta}
|
||||
JOIN $orders_table ON {$wpdb->postmeta}.post_id = $orders_table.id
|
||||
LEFT JOIN $orders_meta_table ON $orders_meta_table.order_id = $orders_table.id AND $orders_meta_table.meta_key = '_payment_tokens'
|
||||
WHERE
|
||||
{$wpdb->postmeta}.meta_key = '_payment_tokens'
|
||||
AND $orders_meta_table.order_id IS NULL
|
||||
";
|
||||
|
||||
// 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.
|
||||
$query =
|
||||
"
|
||||
INSERT INTO $orders_meta_table (order_id, meta_key, meta_value)
|
||||
$select_query
|
||||
LIMIT 250
|
||||
";
|
||||
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared -- No user input in the query, everything hardcoded.
|
||||
$wpdb->query( $query );
|
||||
|
||||
// phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- No user input in the query, everything hardcoded.
|
||||
$has_pending = $wpdb->query( "$select_query LIMIT 1;" );
|
||||
|
||||
return ! empty( $has_pending );
|
||||
}
|
||||
|
||||
@@ -362,6 +362,10 @@ function wc_customer_bought_product( $customer_email, $user_id, $product_id ) {
|
||||
$statuses
|
||||
);
|
||||
$order_table = OrdersTableDataStore::get_orders_table_name();
|
||||
$user_id_clause = '';
|
||||
if ( $user_id ) {
|
||||
$user_id_clause = 'OR o.customer_id = ' . absint( $user_id );
|
||||
}
|
||||
$sql = "
|
||||
SELECT im.meta_value FROM $order_table AS o
|
||||
INNER JOIN {$wpdb->prefix}woocommerce_order_items AS i ON o.id = i.order_id
|
||||
@@ -369,8 +373,7 @@ INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS im ON i.order_item_id =
|
||||
WHERE o.status IN ('" . implode( "','", $statuses ) . "')
|
||||
AND im.meta_key IN ('_product_id', '_variation_id' )
|
||||
AND im.meta_value != 0
|
||||
AND ( o.customer_id IN ('" . implode( "','", $customer_data ) . "') OR o.billing_email IN ('" . implode( "','", $customer_data ) . "') )
|
||||
|
||||
AND ( o.billing_email IN ('" . implode( "','", $customer_data ) . "') $user_id_clause )
|
||||
";
|
||||
$result = $wpdb->get_col( $sql );
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user