diff --git a/includes/admin/list-tables/class-wc-admin-list-table-orders.php b/includes/admin/list-tables/class-wc-admin-list-table-orders.php
index 1b562292c2a..f9babc8825b 100644
--- a/includes/admin/list-tables/class-wc-admin-list-table-orders.php
+++ b/includes/admin/list-tables/class-wc-admin-list-table-orders.php
@@ -772,15 +772,22 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
// Filter the orders by the posted customer.
if ( ! empty( $_GET['_customer_user'] ) ) { // WPCS: input var ok.
- // @codingStandardsIgnoreStart
- $query_vars['meta_query'] = array(
- array(
- 'key' => '_customer_user',
- 'value' => (int) $_GET['_customer_user'], // WPCS: input var ok, sanitization ok.
- 'compare' => '=',
- ),
- );
- // @codingStandardsIgnoreEnd
+ $customer_id = (int) $_GET['_customer_user']; // WPCS: input var ok, sanitization ok.
+
+ // On WC 3.5.0 the ID of the user that placed the order was moved from the post meta _customer_user to the post_author field in the wp_posts table.
+ if ( version_compare( get_option( 'woocommerce_db_version' ), '3.5.0', '>=' ) ) {
+ $query_vars['author'] = $customer_id;
+ } else {
+ // @codingStandardsIgnoreStart
+ $query_vars['meta_query'] = array(
+ array(
+ 'key' => '_customer_user',
+ 'value' => $customer_id,
+ 'compare' => '=',
+ ),
+ );
+ // @codingStandardsIgnoreEnd
+ }
}
// Sorting.
diff --git a/includes/admin/reports/class-wc-report-customers.php b/includes/admin/reports/class-wc-report-customers.php
index 503f470992f..326ad5334f5 100644
--- a/includes/admin/reports/class-wc-report-customers.php
+++ b/includes/admin/reports/class-wc-report-customers.php
@@ -69,46 +69,56 @@ class WC_Report_Customers extends WC_Admin_Report {
* Output customers vs guests chart.
*/
public function customers_vs_guests() {
-
- $customer_order_totals = $this->get_order_report_data(
- array(
- 'data' => array(
- 'ID' => array(
- 'type' => 'post_data',
- 'function' => 'COUNT',
- 'name' => 'total_orders',
- ),
+ $customer_args = array(
+ 'data' => array(
+ 'ID' => array(
+ 'type' => 'post_data',
+ 'function' => 'COUNT',
+ 'name' => 'total_orders',
),
- 'where_meta' => array(
- array(
- 'meta_key' => '_customer_user',
- 'meta_value' => '0',
- 'operator' => '>',
- ),
- ),
- 'filter_range' => true,
- )
+ ),
+ 'filter_range' => true,
);
+ $guest_args = $customer_args;
- $guest_order_totals = $this->get_order_report_data(
- array(
- 'data' => array(
- 'ID' => array(
- 'type' => 'post_data',
- 'function' => 'COUNT',
- 'name' => 'total_orders',
- ),
+ // On WC 3.5.0 the ID of the user that placed the order was moved from the post meta _customer_user to the post_author field in the wp_posts table.
+ if ( version_compare( get_option( 'woocommerce_db_version' ), '3.5.0', '>=' ) ) {
+ $customer_args['where'] = array(
+ array(
+ 'key' => 'post_author',
+ 'value' => '0',
+ 'operator' => '>',
),
- 'where_meta' => array(
- array(
- 'meta_key' => '_customer_user',
- 'meta_value' => '0',
- 'operator' => '=',
- ),
+ );
+
+ $guest_args['where'] = array(
+ array(
+ 'key' => 'post_author',
+ 'value' => '0',
+ 'operator' => '=',
),
- 'filter_range' => true,
- )
- );
+ );
+ } else {
+ $customer_args['where_meta'] = array(
+ array(
+ 'meta_key' => '_customer_user',
+ 'meta_value' => '0',
+ 'operator' => '>',
+ ),
+ );
+
+ $guest_args['where_meta'] = array(
+ array(
+ 'meta_key' => '_customer_user',
+ 'meta_value' => '0',
+ 'operator' => '=',
+ ),
+ );
+ }
+
+ $customer_order_totals = $this->get_order_report_data( $customer_args );
+ $guest_order_totals = $this->get_order_report_data( $guest_args );
+
?>
@@ -246,61 +256,63 @@ class WC_Report_Customers extends WC_Admin_Report {
public function get_main_chart() {
global $wp_locale;
- $customer_orders = $this->get_order_report_data(
- array(
- 'data' => array(
- 'ID' => array(
- 'type' => 'post_data',
- 'function' => 'COUNT',
- 'name' => 'total_orders',
- ),
- 'post_date' => array(
- 'type' => 'post_data',
- 'function' => '',
- 'name' => 'post_date',
- ),
+ $customer_args = array(
+ 'data' => array(
+ 'ID' => array(
+ 'type' => 'post_data',
+ 'function' => 'COUNT',
+ 'name' => 'total_orders',
),
- 'where_meta' => array(
- array(
- 'meta_key' => '_customer_user',
- 'meta_value' => '0',
- 'operator' => '>',
- ),
+ 'post_date' => array(
+ 'type' => 'post_data',
+ 'function' => '',
+ 'name' => 'post_date',
),
- 'group_by' => $this->group_by_query,
- 'order_by' => 'post_date ASC',
- 'query_type' => 'get_results',
- 'filter_range' => true,
- )
+ ),
+ 'group_by' => $this->group_by_query,
+ 'order_by' => 'post_date ASC',
+ 'query_type' => 'get_results',
+ 'filter_range' => true,
);
+ $guest_args = $customer_args;
- $guest_orders = $this->get_order_report_data(
- array(
- 'data' => array(
- 'ID' => array(
- 'type' => 'post_data',
- 'function' => 'COUNT',
- 'name' => 'total_orders',
- ),
- 'post_date' => array(
- 'type' => 'post_data',
- 'function' => '',
- 'name' => 'post_date',
- ),
+ // On WC 3.5.0 the ID of the user that placed the order was moved from the post meta _customer_user to the post_author field in the wp_posts table.
+ if ( version_compare( get_option( 'woocommerce_db_version' ), '3.5.0', '>=' ) ) {
+ $customer_args['where'] = array(
+ array(
+ 'key' => 'post_author',
+ 'value' => '0',
+ 'operator' => '>',
),
- 'where_meta' => array(
- array(
- 'meta_key' => '_customer_user',
- 'meta_value' => '0',
- 'operator' => '=',
- ),
+ );
+
+ $guest_args['where'] = array(
+ array(
+ 'key' => 'post_author',
+ 'value' => '0',
+ 'operator' => '=',
),
- 'group_by' => $this->group_by_query,
- 'order_by' => 'post_date ASC',
- 'query_type' => 'get_results',
- 'filter_range' => true,
- )
- );
+ );
+ } else {
+ $customer_args['where_meta'] = array(
+ array(
+ 'meta_key' => '_customer_user',
+ 'meta_value' => '0',
+ 'operator' => '>',
+ ),
+ );
+
+ $guest_args['where_meta'] = array(
+ array(
+ 'meta_key' => '_customer_user',
+ 'meta_value' => '0',
+ 'operator' => '=',
+ ),
+ );
+ }
+
+ $customer_orders = $this->get_order_report_data( $customer_args );
+ $guest_orders = $this->get_order_report_data( $guest_args );
$signups = $this->prepare_chart_data( $this->customers, 'user_registered', '', $this->chart_interval, $this->start_date, $this->chart_groupby );
$customer_orders = $this->prepare_chart_data( $customer_orders, 'post_date', 'total_orders', $this->chart_interval, $this->start_date, $this->chart_groupby );
diff --git a/includes/api/class-wc-rest-orders-controller.php b/includes/api/class-wc-rest-orders-controller.php
index 02957242ac0..c9121bb4465 100644
--- a/includes/api/class-wc-rest-orders-controller.php
+++ b/includes/api/class-wc-rest-orders-controller.php
@@ -365,15 +365,20 @@ class WC_REST_Orders_Controller extends WC_REST_Legacy_Orders_Controller {
}
if ( isset( $request['customer'] ) ) {
- if ( ! empty( $args['meta_query'] ) ) {
- $args['meta_query'] = array(); // WPCS: slow query ok.
- }
+ // On WC 3.5.0 the ID of the user that placed the order was moved from the post meta _customer_user to the post_author field in the wp_posts table.
+ if ( version_compare( get_option( 'woocommerce_db_version' ), '3.5.0', '>=' ) ) {
+ $args['author'] = $request['customer'];
+ } else {
+ if ( ! empty( $args['meta_query'] ) ) {
+ $args['meta_query'] = array(); // WPCS: slow query ok.
+ }
- $args['meta_query'][] = array(
- 'key' => '_customer_user',
- 'value' => $request['customer'],
- 'type' => 'NUMERIC',
- );
+ $args['meta_query'][] = array(
+ 'key' => '_customer_user',
+ 'value' => $request['customer'],
+ 'type' => 'NUMERIC',
+ );
+ }
}
// Search by product.
diff --git a/includes/api/v1/class-wc-rest-orders-controller.php b/includes/api/v1/class-wc-rest-orders-controller.php
index 804e3fb571e..f617192c0bb 100644
--- a/includes/api/v1/class-wc-rest-orders-controller.php
+++ b/includes/api/v1/class-wc-rest-orders-controller.php
@@ -404,15 +404,20 @@ class WC_REST_Orders_V1_Controller extends WC_REST_Posts_Controller {
}
if ( isset( $request['customer'] ) ) {
- if ( ! empty( $args['meta_query'] ) ) {
- $args['meta_query'] = array();
- }
+ // On WC 3.5.0 the ID of the user that placed the order was moved from the post meta _customer_user to the post_author field in the wp_posts table.
+ if ( version_compare( get_option( 'woocommerce_db_version' ), '3.5.0', '>=' ) ) {
+ $args['author'] = $request['customer'];
+ } else {
+ if ( ! empty( $args['meta_query'] ) ) {
+ $args['meta_query'] = array(); // WPCS: slow query ok.
+ }
- $args['meta_query'][] = array(
- 'key' => '_customer_user',
- 'value' => $request['customer'],
- 'type' => 'NUMERIC',
- );
+ $args['meta_query'][] = array(
+ 'key' => '_customer_user',
+ 'value' => $request['customer'],
+ 'type' => 'NUMERIC',
+ );
+ }
}
// Search by product.
diff --git a/includes/class-wc-background-updater.php b/includes/class-wc-background-updater.php
index 3f80666a767..1c28f7f26da 100644
--- a/includes/class-wc-background-updater.php
+++ b/includes/class-wc-background-updater.php
@@ -132,4 +132,13 @@ class WC_Background_Updater extends WC_Background_Process {
WC_Install::update_db_version();
parent::complete();
}
+
+ /**
+ * See if the batch limit has been exceeded.
+ *
+ * @return bool
+ */
+ public function is_memory_exceeded() {
+ return $this->memory_exceeded();
+ }
}
diff --git a/includes/class-wc-cart-totals.php b/includes/class-wc-cart-totals.php
index bb2c384a113..538977363f0 100644
--- a/includes/class-wc-cart-totals.php
+++ b/includes/class-wc-cart-totals.php
@@ -637,7 +637,7 @@ final class WC_Cart_Totals {
}
if ( $this->calculate_tax && $item->product->is_taxable() ) {
- $total_taxes = WC_Tax::calc_tax( $item->total, $item->tax_rates, $item->price_includes_tax );
+ $total_taxes = apply_filters( 'woocommerce_calculate_item_totals_taxes', WC_Tax::calc_tax( $item->total, $item->tax_rates, $item->price_includes_tax ), $item, $this );
$item->taxes = $total_taxes;
$item->total_tax = array_sum( array_map( array( $this, 'round_line_tax' ), $item->taxes ) );
diff --git a/includes/class-wc-cart.php b/includes/class-wc-cart.php
index d5ea1c5eb9a..293dcf772ec 100644
--- a/includes/class-wc-cart.php
+++ b/includes/class-wc-cart.php
@@ -1385,28 +1385,27 @@ class WC_Cart extends WC_Legacy_Cart {
* @return string price or string for the shipping total
*/
public function get_cart_shipping_total() {
+
+ // Default total assumes Free shipping.
+ $total = __( 'Free!', 'woocommerce' );
+
if ( 0 < $this->get_shipping_total() ) {
if ( $this->display_prices_including_tax() ) {
- $return = wc_price( $this->shipping_total + $this->shipping_tax_total );
+ $total = wc_price( $this->shipping_total + $this->shipping_tax_total );
if ( $this->shipping_tax_total > 0 && ! wc_prices_include_tax() ) {
- $return .= '
' . WC()->countries->inc_tax_or_vat() . '';
+ $total .= '
' . WC()->countries->inc_tax_or_vat() . '';
}
-
- return $return;
} else {
- $return = wc_price( $this->shipping_total );
+ $total = wc_price( $this->shipping_total );
if ( $this->shipping_tax_total > 0 && wc_prices_include_tax() ) {
- $return .= '
' . WC()->countries->ex_tax_or_vat() . '';
+ $total .= '
' . WC()->countries->ex_tax_or_vat() . '';
}
-
- return $return;
}
- } else {
- return __( 'Free!', 'woocommerce' );
}
+ return apply_filters( 'woocommerce_cart_shipping_total', $total, $this );
}
/**
diff --git a/includes/class-wc-emails.php b/includes/class-wc-emails.php
index 207b00c1d84..1ff431bc6c5 100644
--- a/includes/class-wc-emails.php
+++ b/includes/class-wc-emails.php
@@ -223,11 +223,6 @@ class WC_Emails {
$this->emails['WC_Email_Customer_New_Account'] = include 'emails/class-wc-email-customer-new-account.php';
$this->emails = apply_filters( 'woocommerce_email_classes', $this->emails );
-
- // include css inliner.
- if ( ! class_exists( 'Emogrifier' ) && class_exists( 'DOMDocument' ) ) {
- include_once dirname( __FILE__ ) . '/libraries/class-emogrifier.php';
- }
}
/**
diff --git a/includes/class-wc-geolite-integration.php b/includes/class-wc-geolite-integration.php
index 2d97ccd54f8..49e9fc9941f 100644
--- a/includes/class-wc-geolite-integration.php
+++ b/includes/class-wc-geolite-integration.php
@@ -46,7 +46,7 @@ class WC_Geolite_Integration {
/**
* Get country 2-letters ISO by IP address.
- * Retuns empty string when not able to find any ISO code.
+ * Returns empty string when not able to find any ISO code.
*
* @param string $ip_address User IP address.
* @return string
@@ -55,9 +55,12 @@ class WC_Geolite_Integration {
$iso_code = '';
try {
- $reader = new MaxMind\Db\Reader( $this->database ); // phpcs:ignore PHPCompatibility.PHP.NewLanguageConstructs.t_ns_separatorFound
- $data = $reader->get( $ip_address );
- $iso_code = $data['country']['iso_code'];
+ $reader = new MaxMind\Db\Reader( $this->database ); // phpcs:ignore PHPCompatibility.PHP.NewLanguageConstructs.t_ns_separatorFound
+ $data = $reader->get( $ip_address );
+
+ if ( isset( $data['country']['iso_code'] ) ) {
+ $iso_code = $data['country']['iso_code'];
+ }
$reader->close();
} catch ( Exception $e ) {
diff --git a/includes/class-wc-install.php b/includes/class-wc-install.php
index b0bcb358020..e07100c8262 100644
--- a/includes/class-wc-install.php
+++ b/includes/class-wc-install.php
@@ -109,6 +109,10 @@ class WC_Install {
'wc_update_343_cleanup_foreign_keys',
'wc_update_343_db_version',
),
+ '3.5.0' => array(
+ 'wc_update_350_order_customer_id',
+ 'wc_update_350_db_version',
+ ),
);
/**
diff --git a/includes/class-wc-regenerate-images.php b/includes/class-wc-regenerate-images.php
index ae9c371f3dd..c3cb3352817 100644
--- a/includes/class-wc-regenerate-images.php
+++ b/includes/class-wc-regenerate-images.php
@@ -36,11 +36,7 @@ class WC_Regenerate_Images {
public static function init() {
add_action( 'image_get_intermediate_size', array( __CLASS__, 'filter_image_get_intermediate_size' ), 10, 3 );
add_filter( 'wp_generate_attachment_metadata', array( __CLASS__, 'add_uncropped_metadata' ) );
-
- // Resize WooCommerce images on the fly when browsing site through customizer as to showcase image setting changes in real time.
- if ( is_customize_preview() ) {
- add_filter( 'wp_get_attachment_image_src', array( __CLASS__, 'maybe_resize_image' ), 10, 4 );
- }
+ add_filter( 'wp_get_attachment_image_src', array( __CLASS__, 'maybe_resize_image' ), 10, 4 );
// Not required when Jetpack Photon is in use.
if ( method_exists( 'Jetpack', 'is_module_active' ) && Jetpack::is_module_active( 'photon' ) ) {
@@ -206,18 +202,32 @@ class WC_Regenerate_Images {
}
// Use a whitelist of sizes we want to resize. Ignore others.
- if ( ! in_array( $size, apply_filters( 'woocommerce_image_sizes_to_resize', array( 'woocommerce_thumbnail', 'woocommerce_gallery_thumbnail', 'woocommerce_single', 'shop_thumbnail', 'shop_catalog', 'shop_single' ) ), true ) ) {
+ if ( ! $image || ! in_array( $size, apply_filters( 'woocommerce_image_sizes_to_resize', array( 'woocommerce_thumbnail', 'woocommerce_gallery_thumbnail', 'woocommerce_single', 'shop_thumbnail', 'shop_catalog', 'shop_single' ) ), true ) ) {
return $image;
}
- // Get image metadata - we need it to proceed.
- $imagemeta = wp_get_attachment_metadata( $attachment_id );
+ $image_size = wc_get_image_size( $size );
+ $ratio_match = false;
- if ( empty( $imagemeta ) ) {
- return $image;
+ // If '' is passed to either size, we test ratios against the original file. It's uncropped.
+ if ( '' === $image_size['width'] || '' === $image_size['height'] ) {
+ $imagedata = wp_get_attachment_metadata( $attachment_id );
+
+ if ( ! $imagedata ) {
+ return $image;
+ }
+
+ if ( ! isset( $imagedata['file'] ) && isset( $imagedata['sizes']['full'] ) ) {
+ $imagedata['height'] = $imagedata['sizes']['full']['height'];
+ $imagedata['width'] = $imagedata['sizes']['full']['width'];
+ }
+
+ $ratio_match = wp_image_matches_ratio( $image[1], $image[2], $imagedata['width'], $imagedata['height'] );
+ } else {
+ $ratio_match = wp_image_matches_ratio( $image[1], $image[2], $image_size['width'], $image_size['height'] );
}
- if ( ! isset( $imagemeta['sizes'], $imagemeta['sizes'][ $size ] ) || ! self::image_size_matches_settings( $imagemeta['sizes'][ $size ], $size ) ) {
+ if ( ! $ratio_match ) {
return self::resize_and_return_image( $attachment_id, $image, $size, $icon );
}
@@ -316,28 +326,30 @@ class WC_Regenerate_Images {
include ABSPATH . 'wp-admin/includes/image.php';
}
- $thumbnail = self::get_image( $fullsizepath, $image_size['width'], $image_size['height'], $image_size['crop'] );
+ self::$regenerate_size = is_customize_preview() ? $size . '_preview' : $size;
- // If the file is already there perhaps just load it.
- if ( $thumbnail && file_exists( $thumbnail['filename'] ) ) {
- $wp_uploads = wp_upload_dir( null, false );
- $wp_uploads_dir = $wp_uploads['basedir'];
- $wp_uploads_url = $wp_uploads['baseurl'];
+ if ( is_customize_preview() ) {
+ // Make sure registered image size matches the size we're requesting.
+ add_image_size( self::$regenerate_size, absint( $image_size['width'] ), absint( $image_size['height'] ), $image_size['crop'] );
- return array(
- 0 => str_replace( $wp_uploads_dir, $wp_uploads_url, $thumbnail['filename'] ),
- 1 => $thumbnail['width'],
- 2 => $thumbnail['height'],
- );
+ $thumbnail = self::get_image( $fullsizepath, absint( $image_size['width'] ), absint( $image_size['height'] ), $image_size['crop'] );
+
+ // If the file is already there perhaps just load it if we're using the customizer. No need to store in meta data.
+ if ( $thumbnail && file_exists( $thumbnail['filename'] ) ) {
+ $wp_uploads = wp_upload_dir( null, false );
+ $wp_uploads_dir = $wp_uploads['basedir'];
+ $wp_uploads_url = $wp_uploads['baseurl'];
+
+ return array(
+ 0 => str_replace( $wp_uploads_dir, $wp_uploads_url, $thumbnail['filename'] ),
+ 1 => $thumbnail['width'],
+ 2 => $thumbnail['height'],
+ );
+ }
}
$metadata = wp_get_attachment_metadata( $attachment_id );
- // Make sure registered image size matches the size we're requesting.
- add_image_size( $size . '_preview', $image_size['width'], $image_size['height'], $image_size['crop'] );
-
- self::$regenerate_size = $size . '_preview';
-
// We only want to regen a specific image size.
add_filter( 'intermediate_image_sizes', array( __CLASS__, 'adjust_intermediate_image_sizes' ) );
@@ -352,14 +364,13 @@ class WC_Regenerate_Images {
return $image;
}
- // Since this is only a preview we should not update the actual size. That will be done later by the background job.
- if ( isset( $new_metadata['sizes'][ $size . '_preview' ] ) ) {
- $metadata['sizes'][ $size . '_preview' ] = $new_metadata['sizes'][ $size . '_preview' ];
+ if ( isset( $new_metadata['sizes'][ self::$regenerate_size ] ) ) {
+ $metadata['sizes'][ self::$regenerate_size ] = $new_metadata['sizes'][ self::$regenerate_size ];
wp_update_attachment_metadata( $attachment_id, $metadata );
}
// Now we've done our regen, attempt to return the new size.
- $new_image = image_downsize( $attachment_id, $size . '_preview' );
+ $new_image = image_downsize( $attachment_id, self::$regenerate_size );
return $new_image ? $new_image : $image;
}
diff --git a/includes/class-woocommerce.php b/includes/class-woocommerce.php
index a98d4076c85..9f7e1380f85 100644
--- a/includes/class-woocommerce.php
+++ b/includes/class-woocommerce.php
@@ -20,7 +20,7 @@ final class WooCommerce {
*
* @var string
*/
- public $version = '3.4.0';
+ public $version = '3.5.0';
/**
* The single instance of the class.
diff --git a/includes/data-stores/abstract-wc-order-data-store-cpt.php b/includes/data-stores/abstract-wc-order-data-store-cpt.php
index 73ff2844cb0..0d6208887da 100644
--- a/includes/data-stores/abstract-wc-order-data-store-cpt.php
+++ b/includes/data-stores/abstract-wc-order-data-store-cpt.php
@@ -67,7 +67,7 @@ abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP impleme
'post_type' => $order->get_type( 'edit' ),
'post_status' => 'wc-' . ( $order->get_status( 'edit' ) ? $order->get_status( 'edit' ) : apply_filters( 'woocommerce_default_order_status', 'pending' ) ),
'ping_status' => 'closed',
- 'post_author' => 1,
+ 'post_author' => is_callable( array( $order, 'get_customer_id' ) ) ? $order->get_customer_id() : 0,
'post_title' => $this->get_post_title(),
'post_password' => uniqid( 'order_' ),
'post_parent' => $order->get_parent_id( 'edit' ),
@@ -139,7 +139,7 @@ abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP impleme
$changes = $order->get_changes();
// Only update the post when the post data changes.
- if ( array_intersect( array( 'date_created', 'date_modified', 'status', 'parent_id', 'post_excerpt' ), array_keys( $changes ) ) ) {
+ if ( array_intersect( array( 'date_created', 'date_modified', 'status', 'parent_id', 'post_excerpt', 'customer_id' ), array_keys( $changes ) ) ) {
$post_data = array(
'post_date' => gmdate( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getOffsetTimestamp() ),
'post_date_gmt' => gmdate( 'Y-m-d H:i:s', $order->get_date_created( 'edit' )->getTimestamp() ),
@@ -148,6 +148,7 @@ abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP impleme
'post_excerpt' => $this->get_post_excerpt( $order ),
'post_modified' => isset( $changes['date_modified'] ) ? gmdate( 'Y-m-d H:i:s', $order->get_date_modified( 'edit' )->getOffsetTimestamp() ) : current_time( 'mysql' ),
'post_modified_gmt' => isset( $changes['date_modified'] ) ? gmdate( 'Y-m-d H:i:s', $order->get_date_modified( 'edit' )->getTimestamp() ) : current_time( 'mysql', 1 ),
+ 'post_author' => is_callable( array( $order, 'get_customer_id' ) ) ? $order->get_customer_id() : 0,
);
/**
@@ -165,12 +166,27 @@ abstract class Abstract_WC_Order_Data_Store_CPT extends WC_Data_Store_WP impleme
wp_update_post( array_merge( array( 'ID' => $order->get_id() ), $post_data ) );
}
$order->read_meta_data( true ); // Refresh internal meta data, in case things were hooked into `save_post` or another WP hook.
+
+ // If customer changed, update any downloadable permissions.
+ if ( in_array( 'customer_id', $changes ) ) {
+ $this->update_downloadable_permissions( $order );
+ }
}
$this->update_post_meta( $order );
$order->apply_changes();
$this->clear_caches( $order );
}
+ /**
+ * Update downloadable permissions for a given order.
+ *
+ * @param WC_Order $order Order object.
+ */
+ protected function update_downloadable_permissions( $order ) {
+ $data_store = WC_Data_Store::load( 'customer-download' );
+ $data_store->update_user_by_order_id( $order->get_id(), $order->get_customer_id(), $order->get_billing_email() );
+ }
+
/**
* Method to delete an order from the database.
*
diff --git a/includes/data-stores/class-wc-customer-data-store.php b/includes/data-stores/class-wc-customer-data-store.php
index d907e61893c..8ad38340b3f 100644
--- a/includes/data-stores/class-wc-customer-data-store.php
+++ b/includes/data-stores/class-wc-customer-data-store.php
@@ -325,18 +325,27 @@ class WC_Customer_Data_Store extends WC_Data_Store_WP implements WC_Customer_Dat
public function get_last_order( &$customer ) {
global $wpdb;
- $last_order = $wpdb->get_var(
- // phpcs:disable WordPress.WP.PreparedSQL.NotPrepared
- "SELECT posts.ID
+ // On WC 3.5.0 the ID of the user that placed the order was moved from the post meta _customer_user to the post_author field in the wp_posts table.
+ if ( version_compare( get_option( 'woocommerce_db_version' ), '3.5.0', '>=' ) ) {
+ $query = "SELECT ID
+ FROM $wpdb->posts
+ WHERE post_author = '" . esc_sql( $customer->get_id() ) . "'
+ AND post_type = 'shop_order'
+ AND post_status IN ( '" . implode( "','", array_map( 'esc_sql', array_keys( wc_get_order_statuses() ) ) ) . "' )
+ ORDER BY ID DESC";
+ } else {
+ $query = "SELECT posts.ID
FROM $wpdb->posts AS posts
LEFT JOIN {$wpdb->postmeta} AS meta on posts.ID = meta.post_id
WHERE meta.meta_key = '_customer_user'
AND meta.meta_value = '" . esc_sql( $customer->get_id() ) . "'
AND posts.post_type = 'shop_order'
AND posts.post_status IN ( '" . implode( "','", array_map( 'esc_sql', array_keys( wc_get_order_statuses() ) ) ) . "' )
- ORDER BY posts.ID DESC"
- // phpcs:enable
- );
+ ORDER BY posts.ID DESC";
+ }
+
+ // phpcs:ignore WordPress.WP.PreparedSQL.NotPrepared
+ $last_order = $wpdb->get_var( $query );
if ( ! $last_order ) {
return false;
@@ -358,17 +367,25 @@ class WC_Customer_Data_Store extends WC_Data_Store_WP implements WC_Customer_Dat
if ( '' === $count ) {
global $wpdb;
- $count = $wpdb->get_var(
- // phpcs:disable WordPress.WP.PreparedSQL.NotPrepared
- "SELECT COUNT(*)
+ // On WC 3.5.0 the ID of the user that placed the order was moved from the post meta _customer_user to the post_author field in the wp_posts table.
+ if ( version_compare( get_option( 'woocommerce_db_version' ), '3.5.0', '>=' ) ) {
+ $query = "SELECT COUNT(*)
+ FROM $wpdb->posts
+ WHERE post_type = 'shop_order'
+ AND post_status IN ( '" . implode( "','", array_map( 'esc_sql', array_keys( wc_get_order_statuses() ) ) ) . "' )
+ AND post_author = " . esc_sql( $customer->get_id() );
+ } else {
+ $query = "SELECT COUNT(*)
FROM $wpdb->posts as posts
LEFT JOIN {$wpdb->postmeta} AS meta ON posts.ID = meta.post_id
WHERE meta.meta_key = '_customer_user'
AND posts.post_type = 'shop_order'
AND posts.post_status IN ( '" . implode( "','", array_map( 'esc_sql', array_keys( wc_get_order_statuses() ) ) ) . "' )
- AND meta_value = '" . esc_sql( $customer->get_id() ) . "'"
- // phpcs:enable
- );
+ AND meta_value = '" . esc_sql( $customer->get_id() ) . "'";
+ }
+
+ // phpcs:ignore WordPress.WP.PreparedSQL.NotPrepared
+ $count = $wpdb->get_var( $query );
update_user_meta( $customer->get_id(), '_order_count', $count );
}
@@ -393,11 +410,18 @@ class WC_Customer_Data_Store extends WC_Data_Store_WP implements WC_Customer_Dat
global $wpdb;
$statuses = array_map( 'esc_sql', wc_get_is_paid_statuses() );
- $spent = $wpdb->get_var(
- // phpcs:disable WordPress.WP.PreparedSQL.NotPrepared
- apply_filters(
- 'woocommerce_customer_get_total_spent_query',
- "SELECT SUM(meta2.meta_value)
+
+ // On WC 3.5.0 the ID of the user that placed the order was moved from the post meta _customer_user to the post_author field in the wp_posts table.
+ if ( version_compare( get_option( 'woocommerce_db_version' ), '3.5.0', '>=' ) ) {
+ $query = "SELECT SUM(meta.meta_value)
+ FROM $wpdb->posts as posts
+ LEFT JOIN {$wpdb->postmeta} AS meta ON posts.ID = meta.post_id
+ WHERE posts.post_author = '" . esc_sql( $customer->get_id() ) . "'
+ AND posts.post_type = 'shop_order'
+ AND posts.post_status IN ( 'wc-" . implode( "','wc-", $statuses ) . "' )
+ AND meta.meta_key = '_order_total'";
+ } else {
+ $query = "SELECT SUM(meta2.meta_value)
FROM $wpdb->posts as posts
LEFT JOIN {$wpdb->postmeta} AS meta ON posts.ID = meta.post_id
LEFT JOIN {$wpdb->postmeta} AS meta2 ON posts.ID = meta2.post_id
@@ -405,11 +429,11 @@ class WC_Customer_Data_Store extends WC_Data_Store_WP implements WC_Customer_Dat
AND meta.meta_value = '" . esc_sql( $customer->get_id() ) . "'
AND posts.post_type = 'shop_order'
AND posts.post_status IN ( 'wc-" . implode( "','wc-", $statuses ) . "' )
- AND meta2.meta_key = '_order_total'",
- $customer
- )
- // phpcs:enable
- );
+ AND meta2.meta_key = '_order_total'";
+ }
+
+ // phpcs:ignore WordPress.WP.PreparedSQL.NotPrepared
+ $spent = $wpdb->get_var( apply_filters( 'woocommerce_customer_get_total_spent_query', $query, $customer ) );
if ( ! $spent ) {
$spent = 0;
diff --git a/includes/data-stores/class-wc-order-data-store-cpt.php b/includes/data-stores/class-wc-order-data-store-cpt.php
index 2cc5b7e1fcd..316aa4b8373 100644
--- a/includes/data-stores/class-wc-order-data-store-cpt.php
+++ b/includes/data-stores/class-wc-order-data-store-cpt.php
@@ -107,10 +107,17 @@ class WC_Order_Data_Store_CPT extends Abstract_WC_Order_Data_Store_CPT implement
$date_paid = get_post_meta( $id, '_paid_date', true );
}
+ // On WC 3.5.0 the ID of the user that placed the order was moved from the post meta _customer_user to the post_author field in the wp_posts table.
+ if ( version_compare( get_option( 'woocommerce_db_version' ), '3.5.0', '>=' ) ) {
+ $customer_id = $post_object->post_author;
+ } else {
+ $customer_id = get_post_meta( $id, '_customer_user', true );
+ }
+
$order->set_props(
array(
'order_key' => get_post_meta( $id, '_order_key', true ),
- 'customer_id' => get_post_meta( $id, '_customer_user', true ),
+ 'customer_id' => $customer_id,
'billing_first_name' => get_post_meta( $id, '_billing_first_name', true ),
'billing_last_name' => get_post_meta( $id, '_billing_last_name', true ),
'billing_company' => get_post_meta( $id, '_billing_company', true ),
@@ -258,10 +265,9 @@ class WC_Order_Data_Store_CPT extends Abstract_WC_Order_Data_Store_CPT implement
update_post_meta( $id, '_shipping_address_index', implode( ' ', $order->get_address( 'shipping' ) ) );
}
- // If customer changed, update any downloadable permissions.
- if ( in_array( 'customer_id', $updated_props, true ) || in_array( 'billing_email', $updated_props, true ) ) {
- $data_store = WC_Data_Store::load( 'customer-download' );
- $data_store->update_user_by_order_id( $id, $order->get_customer_id(), $order->get_billing_email() );
+ // If customer email changed, update any downloadable permissions.
+ if ( in_array( 'billing_email', $updated_props ) ) {
+ $this->update_downloadable_permissions( $order );
}
// Mark user account as active.
@@ -645,6 +651,11 @@ class WC_Order_Data_Store_CPT extends Abstract_WC_Order_Data_Store_CPT implement
'page' => 'paged',
);
+ // On WC 3.5.0 the ID of the user that placed the order was moved from the post meta _customer_user to the post_author field in the wp_posts table.
+ if ( version_compare( get_option( 'woocommerce_db_version' ), '3.5.0', '>=' ) ) {
+ $key_mapping['customer_id'] = 'author';
+ }
+
foreach ( $key_mapping as $query_key => $db_key ) {
if ( isset( $query_vars[ $query_key ] ) ) {
$query_vars[ $db_key ] = $query_vars[ $query_key ];
diff --git a/includes/emails/class-wc-email.php b/includes/emails/class-wc-email.php
index c7d72fa3bc4..fd36a929e90 100644
--- a/includes/emails/class-wc-email.php
+++ b/includes/emails/class-wc-email.php
@@ -510,28 +510,45 @@ class WC_Email extends WC_Settings_API {
/**
* Apply inline styles to dynamic content.
*
+ * We only inline CSS for html emails, and to do so we use Emogrifier library (if supported).
+ *
* @param string|null $content Content that will receive inline styles.
* @return string
*/
public function style_inline( $content ) {
- // make sure we only inline CSS for html emails.
- if ( in_array( $this->get_content_type(), array( 'text/html', 'multipart/alternative' ), true ) && class_exists( 'DOMDocument' ) ) {
+ if ( in_array( $this->get_content_type(), array( 'text/html', 'multipart/alternative' ), true ) ) {
ob_start();
wc_get_template( 'emails/email-styles.php' );
$css = apply_filters( 'woocommerce_email_styles', ob_get_clean() );
- // apply CSS styles inline for picky email clients.
- try {
- $emogrifier = new Emogrifier( $content, $css );
- $content = $emogrifier->emogrify();
- } catch ( Exception $e ) {
- $logger = wc_get_logger();
- $logger->error( $e->getMessage(), array( 'source' => 'emogrifier' ) );
+ if ( $this->supports_emogrifier() ) {
+ if ( ! class_exists( 'Emogrifier' ) ) {
+ include_once dirname( dirname( __FILE__ ) ) . '/libraries/class-emogrifier.php';
+ }
+ try {
+ $emogrifier = new Emogrifier( $content, $css );
+ $content = $emogrifier->emogrify();
+ } catch ( Exception $e ) {
+ $logger = wc_get_logger();
+ $logger->error( $e->getMessage(), array( 'source' => 'emogrifier' ) );
+ }
+ } else {
+ $content = '' . $content;
}
}
return $content;
}
+ /**
+ * Return if emogrifier library is supported.
+ *
+ * @since 3.5.0
+ * @return bool
+ */
+ protected function supports_emogrifier() {
+ return class_exists( 'DOMDocument' ) && version_compare( PHP_VERSION, '5.5', '>=' );
+ }
+
/**
* Get the email content in plain text format.
*
diff --git a/includes/libraries/class-emogrifier.php b/includes/libraries/class-emogrifier.php
index 490c2586ce2..12d6c82722a 100644
--- a/includes/libraries/class-emogrifier.php
+++ b/includes/libraries/class-emogrifier.php
@@ -4,1552 +4,1808 @@
*
* For more information, please see the README.md file.
*
- * @version 1.2.0
+ * @version 2.0.0
*
* @author Cameron Brooks
* @author Jaime Prado
- * @author Oliver Klee
+ * @author Oliver Klee
* @author Roman Ožana
* @author Sander Kruger
+ * @author Zoli Szabó
*/
-// @codingStandardsIgnoreFile
class Emogrifier
{
- /**
- * @var int
- */
- const CACHE_KEY_CSS = 0;
-
- /**
- * @var int
- */
- const CACHE_KEY_SELECTOR = 1;
-
- /**
- * @var int
- */
- const CACHE_KEY_XPATH = 2;
-
- /**
- * @var int
- */
- const CACHE_KEY_CSS_DECLARATIONS_BLOCK = 3;
-
- /**
- * @var int
- */
- const CACHE_KEY_COMBINED_STYLES = 4;
-
- /**
- * for calculating nth-of-type and nth-child selectors
- *
- * @var int
- */
- const INDEX = 0;
-
- /**
- * for calculating nth-of-type and nth-child selectors
- *
- * @var int
- */
- const MULTIPLIER = 1;
-
- /**
- * @var string
- */
- const ID_ATTRIBUTE_MATCHER = '/(\\w+)?\\#([\\w\\-]+)/';
-
- /**
- * @var string
- */
- const CLASS_ATTRIBUTE_MATCHER = '/(\\w+|[\\*\\]])?((\\.[\\w\\-]+)+)/';
-
- /**
- * @var string
- */
- const CONTENT_TYPE_META_TAG = '';
-
- /**
- * @var string
- */
- const DEFAULT_DOCUMENT_TYPE = '';
-
- /**
- * @var string
- */
- private $html = '';
-
- /**
- * @var string
- */
- private $css = '';
-
- /**
- * @var bool[]
- */
- private $excludedSelectors = array();
-
- /**
- * @var string[]
- */
- private $unprocessableHtmlTags = array( 'wbr' );
-
- /**
- * @var bool[]
- */
- private $allowedMediaTypes = array( 'all' => true, 'screen' => true, 'print' => true );
-
- /**
- * @var mixed[]
- */
- private $caches = array(
- self::CACHE_KEY_CSS => array(),
- self::CACHE_KEY_SELECTOR => array(),
- self::CACHE_KEY_XPATH => array(),
- self::CACHE_KEY_CSS_DECLARATIONS_BLOCK => array(),
- self::CACHE_KEY_COMBINED_STYLES => array(),
- );
-
- /**
- * the visited nodes with the XPath paths as array keys
- *
- * @var \DOMElement[]
- */
- private $visitedNodes = array();
-
- /**
- * the styles to apply to the nodes with the XPath paths as array keys for the outer array
- * and the attribute names/values as key/value pairs for the inner array
- *
- * @var string[][]
- */
- private $styleAttributesForNodes = array();
-
- /**
- * Determines whether the "style" attributes of tags in the the HTML passed to this class should be preserved.
- * If set to false, the value of the style attributes will be discarded.
- *
- * @var bool
- */
- private $isInlineStyleAttributesParsingEnabled = true;
-
- /**
- * Determines whether the