Merge remote-tracking branch 'upstream/master'

This commit is contained in:
Josh Smith 2017-08-11 05:00:52 +00:00
commit 9e06209277
8 changed files with 239 additions and 111 deletions

View File

@ -274,6 +274,39 @@ final class WC_Cart_Totals {
*/
protected function set_coupons() {
$this->coupons = $this->object->get_coupons();
foreach ( $this->coupons as $coupon ) {
switch ( $coupon->get_discount_type() ) {
case 'fixed_product' :
$coupon->sort = 1;
break;
case 'percent' :
$coupon->sort = 2;
break;
case 'fixed_cart' :
$coupon->sort = 3;
break;
default:
$coupon->sort = 0;
break;
}
}
uasort( $this->coupons, array( $this, 'sort_coupons' ) );
}
/**
* Sort coupons so discounts apply consistently.
*
* @param WC_Coupon $a
* @param WC_Coupon $b
* @return int
*/
protected function sort_coupons( $a, $b ) {
if ( $a->sort === $b->sort ) {
return $a->get_id() - $b->get_id();
}
return ( $a->sort < $b->sort ) ? -1 : 1;
}
/**

View File

@ -303,25 +303,27 @@ class WC_Order extends WC_Abstract_Order {
* Handle the status transition.
*/
protected function status_transition() {
if ( $this->status_transition ) {
do_action( 'woocommerce_order_status_' . $this->status_transition['to'], $this->get_id(), $this );
$status_transition = $this->status_transition;
if ( ! empty( $this->status_transition['from'] ) ) {
// Reset status transition variable
$this->status_transition = false;
if ( $status_transition ) {
do_action( 'woocommerce_order_status_' . $status_transition['to'], $this->get_id(), $this );
if ( ! empty( $status_transition['from'] ) ) {
/* translators: 1: old order status 2: new order status */
$transition_note = sprintf( __( 'Order status changed from %1$s to %2$s.', 'woocommerce' ), wc_get_order_status_name( $this->status_transition['from'] ), wc_get_order_status_name( $this->status_transition['to'] ) );
$transition_note = sprintf( __( 'Order status changed from %1$s to %2$s.', 'woocommerce' ), wc_get_order_status_name( $status_transition['from'] ), wc_get_order_status_name( $status_transition['to'] ) );
do_action( 'woocommerce_order_status_' . $this->status_transition['from'] . '_to_' . $this->status_transition['to'], $this->get_id(), $this );
do_action( 'woocommerce_order_status_changed', $this->get_id(), $this->status_transition['from'], $this->status_transition['to'], $this );
do_action( 'woocommerce_order_status_' . $status_transition['from'] . '_to_' . $status_transition['to'], $this->get_id(), $this );
do_action( 'woocommerce_order_status_changed', $this->get_id(), $status_transition['from'], $status_transition['to'], $this );
} else {
/* translators: %s: new order status */
$transition_note = sprintf( __( 'Order status set to %s.', 'woocommerce' ), wc_get_order_status_name( $this->status_transition['to'] ) );
$transition_note = sprintf( __( 'Order status set to %s.', 'woocommerce' ), wc_get_order_status_name( $status_transition['to'] ) );
}
// Note the transition occurred
$this->add_order_note( trim( $this->status_transition['note'] . ' ' . $transition_note ), 0, $this->status_transition['manual'] );
// This has ran, so reset status transition variable
$this->status_transition = false;
$this->add_order_note( trim( $status_transition['note'] . ' ' . $transition_note ), 0, $status_transition['manual'] );
}
}

View File

@ -125,17 +125,17 @@ class WC_Product_CSV_Importer extends WC_Product_Importer {
* If mapping to a SKU and the product ID does not exist, a temporary object
* will be created so it can be updated later.
*
* @param string $field Field value.
* @param string $value Field value.
* @return int|string
*/
public function parse_relative_field( $field ) {
public function parse_relative_field( $value ) {
global $wpdb;
if ( empty( $field ) ) {
if ( empty( $value ) ) {
return '';
}
if ( preg_match( '/^id:(\d+)$/', $field, $matches ) ) {
if ( preg_match( '/^id:(\d+)$/', $value, $matches ) ) {
$id = intval( $matches[1] );
$original_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = '_original_id' AND meta_value = %s;", $id ) );
@ -154,15 +154,15 @@ class WC_Product_CSV_Importer extends WC_Product_Importer {
return $id;
}
if ( $id = wc_get_product_id_by_sku( $field ) ) {
if ( $id = wc_get_product_id_by_sku( $value ) ) {
return $id;
}
try {
$product = new WC_Product_Simple();
$product->set_name( 'Import placeholder for ' . $field );
$product->set_name( 'Import placeholder for ' . $value );
$product->set_status( 'importing' );
$product->set_sku( $field );
$product->set_sku( $value );
$id = $product->save();
if ( $id && ! is_wp_error( $id ) ) {
@ -181,13 +181,13 @@ class WC_Product_CSV_Importer extends WC_Product_Importer {
* If we're not doing an update, create a placeholder product so mapping works
* for rows following this one.
*
* @param stirng $field
* @param string $value Field value.
* @return int
*/
public function parse_id_field( $field ) {
public function parse_id_field( $value ) {
global $wpdb;
$id = absint( $field );
$id = absint( $value );
if ( ! $id ) {
return 0;
@ -225,77 +225,77 @@ class WC_Product_CSV_Importer extends WC_Product_Importer {
/**
* Parse relative comma-delineated field and return product ID.
*
* @param string $field Field value.
* @param string $value Field value.
* @return array
*/
public function parse_relative_comma_field( $field ) {
if ( empty( $field ) ) {
public function parse_relative_comma_field( $value ) {
if ( empty( $value ) ) {
return array();
}
return array_filter( array_map( array( $this, 'parse_relative_field' ), $this->explode_values( $field ) ) );
return array_filter( array_map( array( $this, 'parse_relative_field' ), $this->explode_values( $value ) ) );
}
/**
* Parse a comma-delineated field from a CSV.
*
* @param string $field Field value.
* @param string $value Field value.
* @return array
*/
public function parse_comma_field( $field ) {
if ( empty( $field ) ) {
public function parse_comma_field( $value ) {
if ( empty( $value ) ) {
return array();
}
return array_map( 'wc_clean', $this->explode_values( $field ) );
return array_map( 'wc_clean', $this->explode_values( $value ) );
}
/**
* Parse a field that is generally '1' or '0' but can be something else.
*
* @param string $field Field value.
* @param string $value Field value.
* @return bool|string
*/
public function parse_bool_field( $field ) {
if ( '0' === $field ) {
public function parse_bool_field( $value ) {
if ( '0' === $value ) {
return false;
}
if ( '1' === $field ) {
if ( '1' === $value ) {
return true;
}
// Don't return explicit true or false for empty fields or values like 'notify'.
return wc_clean( $field );
return wc_clean( $value );
}
/**
* Parse a float value field.
*
* @param string $field Field value.
* @param string $value Field value.
* @return float|string
*/
public function parse_float_field( $field ) {
if ( '' === $field ) {
return $field;
public function parse_float_field( $value ) {
if ( '' === $value ) {
return $value;
}
return floatval( $field );
return floatval( $value );
}
/**
* Parse a category field from a CSV.
* Categories are separated by commas and subcategories are "parent > subcategory".
*
* @param string $field Field value.
* @param string $value Field value.
* @return array of arrays with "parent" and "name" keys.
*/
public function parse_categories_field( $field ) {
if ( empty( $field ) ) {
public function parse_categories_field( $value ) {
if ( empty( $value ) ) {
return array();
}
$row_terms = $this->explode_values( $field );
$row_terms = $this->explode_values( $value );
$categories = array();
foreach ( $row_terms as $row_term ) {
@ -332,15 +332,15 @@ class WC_Product_CSV_Importer extends WC_Product_Importer {
/**
* Parse a tag field from a CSV.
*
* @param string $field Field value.
* @param string $value Field value.
* @return array
*/
public function parse_tags_field( $field ) {
if ( empty( $field ) ) {
public function parse_tags_field( $value ) {
if ( empty( $value ) ) {
return array();
}
$names = $this->explode_values( $field );
$names = $this->explode_values( $value );
$tags = array();
foreach ( $names as $name ) {
@ -359,18 +359,18 @@ class WC_Product_CSV_Importer extends WC_Product_Importer {
/**
* Parse a shipping class field from a CSV.
*
* @param string $field Field value.
* @param string $value Field value.
* @return int
*/
public function parse_shipping_class_field( $field ) {
if ( empty( $field ) ) {
public function parse_shipping_class_field( $value ) {
if ( empty( $value ) ) {
return 0;
}
$term = get_term_by( 'name', $field, 'product_shipping_class' );
$term = get_term_by( 'name', $value, 'product_shipping_class' );
if ( ! $term || is_wp_error( $term ) ) {
$term = (object) wp_insert_term( $field, 'product_shipping_class' );
$term = (object) wp_insert_term( $value, 'product_shipping_class' );
}
return $term->term_id;
@ -379,17 +379,17 @@ class WC_Product_CSV_Importer extends WC_Product_Importer {
/**
* Parse images list from a CSV. Images can be filenames or URLs.
*
* @param string $field Field value.
* @param string $value Field value.
* @return array
*/
public function parse_images_field( $field ) {
if ( empty( $field ) ) {
public function parse_images_field( $value ) {
if ( empty( $value ) ) {
return array();
}
$images = array();
foreach ( $this->explode_values( $field ) as $image ) {
foreach ( $this->explode_values( $value ) as $image ) {
if ( stristr( $image, '://' ) ) {
$images[] = esc_url_raw( $image );
} else {
@ -404,17 +404,17 @@ class WC_Product_CSV_Importer extends WC_Product_Importer {
* Parse dates from a CSV.
* Dates requires the format YYYY-MM-DD and time is optional.
*
* @param string $field Field value.
* @param string $value Field value.
* @return string|null
*/
public function parse_date_field( $field ) {
if ( empty( $field ) ) {
public function parse_date_field( $value ) {
if ( empty( $value ) ) {
return null;
}
if ( preg_match( '/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])([ 01-9:]*)$/', $field ) ) {
if ( preg_match( '/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])([ 01-9:]*)$/', $value ) ) {
// Don't include the time if the field had time in it.
return current( explode( ' ', $field ) );
return current( explode( ' ', $value ) );
}
return null;
@ -423,25 +423,38 @@ class WC_Product_CSV_Importer extends WC_Product_Importer {
/**
* Parse backorders from a CSV.
*
* @param string $field Field value.
* @param string $value Field value.
* @return string
*/
public function parse_backorders_field( $field ) {
if ( empty( $field ) ) {
public function parse_backorders_field( $value ) {
if ( empty( $value ) ) {
return '';
}
$field = $this->parse_bool_field( $field );
$value = $this->parse_bool_field( $value );
if ( 'notify' === $field ) {
if ( 'notify' === $value ) {
return 'notify';
} elseif ( is_bool( $field ) ) {
return $field ? 'yes' : 'no';
} elseif ( is_bool( $value ) ) {
return $value ? 'yes' : 'no';
}
return '';
}
/**
* Just skip current field.
*
* By default is applied wc_clean() to all not listed fields
* in self::get_formating_callback(), use this method to skip any formating.
*
* @param string $value Field value.
* @return string
*/
public function parse_skip_field( $value ) {
return $value;
}
/**
* Get formatting callback.
*
@ -460,9 +473,9 @@ class WC_Product_CSV_Importer extends WC_Product_Importer {
'featured' => array( $this, 'parse_bool_field' ),
'date_on_sale_from' => array( $this, 'parse_date_field' ),
'date_on_sale_to' => array( $this, 'parse_date_field' ),
'name' => 'wp_filter_post_kses',
'short_description' => 'wp_filter_post_kses',
'description' => 'wp_filter_post_kses',
'name' => array( $this, 'parse_skip_field' ),
'short_description' => array( $this, 'parse_skip_field' ),
'description' => array( $this, 'parse_skip_field' ),
'manage_stock' => array( $this, 'parse_bool_field' ),
'backorders' => array( $this, 'parse_backorders_field' ),
'stock_status' => array( $this, 'parse_bool_field' ),

View File

@ -157,35 +157,8 @@ class WC_Shortcode_Checkout {
if ( $order->needs_payment() ) {
?>
<ul class="order_details">
<li class="order">
<?php _e( 'Order number:', 'woocommerce' ); ?>
<strong><?php echo $order->get_order_number(); ?></strong>
</li>
<li class="date">
<?php _e( 'Date:', 'woocommerce' ); ?>
<strong><?php echo wc_format_datetime( $order->get_date_created() ); ?></strong>
</li>
<li class="total">
<?php _e( 'Total:', 'woocommerce' ); ?>
<strong><?php echo $order->get_formatted_order_total(); ?></strong>
</li>
<?php if ( $order->get_payment_method_title() ) : ?>
<li class="method">
<?php _e( 'Payment method:', 'woocommerce' ); ?>
<strong><?php
echo wp_kses_post( $order->get_payment_method_title() );
?></strong>
</li>
<?php endif; ?>
</ul>
<?php do_action( 'woocommerce_receipt_' . $order->get_payment_method(), $order_id ); ?>
<div class="clear"></div>
<?php
wc_get_template( 'checkout/order-receipt.php', array( 'order' => $order ) );
} else {
wc_add_notice( sprintf( __( 'This order&rsquo;s status is &ldquo;%s&rdquo;&mdash;it cannot be paid for. Please contact us if you need assistance.', 'woocommerce' ), wc_get_order_status_name( $order->get_status() ) ), 'error' );
}

View File

@ -369,7 +369,19 @@ function wc_cart_round_discount( $value, $precision ) {
if ( version_compare( PHP_VERSION, '5.3.0', '>=' ) ) {
return round( $value, $precision, WC_DISCOUNT_ROUNDING_MODE );
} else {
return round( $value, $precision );
// Fake it in PHP 5.2.
if ( 2 === WC_DISCOUNT_ROUNDING_MODE && strstr( $value, '.' ) ) {
$value = (string) $value;
$value = explode( '.', $value );
$value[1] = substr( $value[1], 0, $precision + 1 );
$value = implode( '.', $value );
if ( substr( $value, -1 ) === '5' ) {
$value = substr( $value, 0, -1 ) . '4';
}
$value = floatval( $value );
}
return round( $value, $precision );
}
}

View File

@ -216,21 +216,32 @@ function wc_trim_zeros( $price ) {
/**
* Round a tax amount.
*
* @param double $tax Amount to round.
* @param int $dp DP to round. Defaults to wc_get_price_decimals.
* @param double $value Amount to round.
* @param int $precision DP to round. Defaults to wc_get_price_decimals.
* @return double
*/
function wc_round_tax_total( $tax, $dp = null ) {
$dp = is_null( $dp ) ? wc_get_price_decimals() : absint( $dp );
function wc_round_tax_total( $value, $precision = null ) {
$precision = is_null( $precision ) ? wc_get_price_decimals() : absint( $precision );
// @codeCoverageIgnoreStart
if ( version_compare( phpversion(), '5.3', '<' ) ) {
$rounded_tax = round( $tax, $dp );
if ( version_compare( PHP_VERSION, '5.3.0', '>=' ) ) {
$rounded_tax = round( $value, $precision, WC_TAX_ROUNDING_MODE );
} else {
// @codeCoverageIgnoreEnd
$rounded_tax = round( $tax, $dp, WC_TAX_ROUNDING_MODE );
// Fake it in PHP 5.2.
if ( 2 === WC_TAX_ROUNDING_MODE && strstr( $value, '.' ) ) {
$value = (string) $value;
$value = explode( '.', $value );
$value[1] = substr( $value[1], 0, $precision + 1 );
$value = implode( '.', $value );
if ( substr( $value, -1 ) === '5' ) {
$value = substr( $value, 0, -1 ) . '4';
}
$value = floatval( $value );
}
$rounded_tax = round( $value, $precision );
}
return apply_filters( 'wc_round_tax_total', $rounded_tax, $tax, $dp, WC_TAX_ROUNDING_MODE );
return apply_filters( 'wc_round_tax_total', $rounded_tax, $value, $precision, WC_TAX_ROUNDING_MODE );
}
/**

View File

@ -162,6 +162,43 @@ Yes you can! Join in on our [GitHub repository](http://github.com/woocommerce/wo
== Changelog ==
= 3.2.0 - 2017-XX-XX =
* Feature - Simplified the ability to resend order details to customers with a single "Resend Order Details" action.
* Feature - Added store street address, city and postal code to settings for use by plugins.
* Feature - wrapping values in quotes now let's you use commas in the product CSV importer.
* Feature - If a fatal error occurs, WooCommerce will catch and log it to be viewed in WC > Status > Logs.
* Feature - Drag and drop sorting on the grouped product field to control display order.
* Feature - Integrated selectWoo; more accessible Select2 (enhanced select boxes) in admin and on the frontend.
* Feature - Enhanced select boxes in the shipping calculator.
* Feature - Enhanced select boxes in layered nav "or" widget.
* Feature - Ajaxified the product category filter on the products screen.
* Tweak - Made the buyer phone number clickable in the in the order backend.
* Tweak - Clean up user is_paying_customer after deleting an order.
* Tweak - If stock changes between page load and editing, reject stock changes to avoid incorrect stock changes.
* Tweak - Disable search engines indexing core, dynamic, cart/checkout pages.
* Tweak - Added shortcodes to description output in structured data, and improved variable product data.
* Tweak - Use ajax when restoring an item in the cart, and removing an item from the mini-cart.
* Tweak - Onboarding: added "next" button to pointers and allowed them to be dismissed.
* Tweak - Display post states for WC pages e.g. shop, checkout etc.
* Tweak - Improved order tracking page display and validation.
* Dev - Product CRUD search helpers.
* Dev - Refactor shipping rate to include instance IDs.
* Dev - New attribute helper functions.
* Dev - Order note helper functions.
* Dev - Added the "Terms and conditions" page to the api system status report.
* Dev - Made date inputs reusable.
* Dev - Added option for merging when using 'Order Again' via filter woocommerce_empty_cart_when_order_again.
* Dev - Added tool for repopulating order address search indexes.
* Dev - Added woocommerce_get_asset_url filter.
* Dev - Show notice when internal meta props are accessed directly.
* Dev - Improve meta data updates so data is only updated when changed.
* Dev - Improved get_filtered_term_product_counts performance.
* Dev - Introduced wc_get_account_orders_actions function.
* Theming - Display downloads in their own table, universally, using a new template file.
* Theming - Checkout: Order pay template
* Localization - Added cantons of Switzerland.
* Localization - Add rtl support for activation.css.
* Localization - Updated Mexican states to use correct 2 letter codes.
* Many smaller fixes and improvements - see Github!
[See changelog for all versions](https://raw.githubusercontent.com/woocommerce/woocommerce/master/CHANGELOG.txt).

View File

@ -0,0 +1,47 @@
<?php
/**
* Checkout Order Receipt Template
*
* This template can be overridden by copying it to yourtheme/woocommerce/checkout/order-receipt.php.
*
* HOWEVER, on occasion WooCommerce will need to update template files and you
* (the theme developer) will need to copy the new files to your theme to
* maintain compatibility. We try to do this as little as possible, but it does
* happen. When this occurs the version of the template file will be bumped and
* the readme will list any important changes.
*
* @see https://docs.woocommerce.com/document/template-structure/
* @author WooThemes
* @package WooCommerce/Templates
* @version 3.2.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
?>
<ul class="order_details">
<li class="order">
<?php esc_html_e( 'Order number:', 'woocommerce' ); ?>
<strong><?php echo esc_html( $order->get_order_number() ); ?></strong>
</li>
<li class="date">
<?php esc_html_e( 'Date:', 'woocommerce' ); ?>
<strong><?php echo esc_html( wc_format_datetime( $order->get_date_created() ) ); ?></strong>
</li>
<li class="total">
<?php esc_html_e( 'Total:', 'woocommerce' ); ?>
<strong><?php echo wp_kses_post( $order->get_formatted_order_total() ); ?></strong>
</li>
<?php if ( $order->get_payment_method_title() ) : ?>
<li class="method">
<?php esc_html_e( 'Payment method:', 'woocommerce' ); ?>
<strong><?php echo wp_kses_post( $order->get_payment_method_title() ); ?></strong>
</li>
<?php endif; ?>
</ul>
<?php do_action( 'woocommerce_receipt_' . $order->get_payment_method(), $order_id ); ?>
<div class="clear"></div>