Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
d420fcca29
|
@ -575,33 +575,29 @@ abstract class WC_Abstract_Order {
|
|||
* @return bool success or fail
|
||||
*/
|
||||
public function calculate_taxes() {
|
||||
|
||||
$tax_total = 0;
|
||||
$taxes = array();
|
||||
$tax_based_on = get_option( 'woocommerce_tax_based_on' );
|
||||
|
||||
if ( 'base' === $tax_based_on ) {
|
||||
if ( 'billing' === $tax_based_on ) {
|
||||
$country = $this->billing_country;
|
||||
$state = $this->billing_state;
|
||||
$postcode = $this->billing_postcode;
|
||||
$city = $this->billing_city;
|
||||
} elseif ( 'shipping' === $tax_based_on ) {
|
||||
$country = $this->shipping_country;
|
||||
$state = $this->shipping_state;
|
||||
$postcode = $this->shipping_postcode;
|
||||
$city = $this->shipping_city;
|
||||
}
|
||||
|
||||
// Default to base
|
||||
if ( 'base' === $tax_based_on || empty( $country ) ) {
|
||||
$default = wc_get_base_location();
|
||||
$country = $default['country'];
|
||||
$state = $default['state'];
|
||||
$postcode = '';
|
||||
$city = '';
|
||||
|
||||
} elseif ( 'billing' === $tax_based_on ) {
|
||||
|
||||
$country = $this->billing_country;
|
||||
$state = $this->billing_state;
|
||||
$postcode = $this->billing_postcode;
|
||||
$city = $this->billing_city;
|
||||
|
||||
} else {
|
||||
|
||||
$country = $this->shipping_country;
|
||||
$state = $this->shipping_state;
|
||||
$postcode = $this->shipping_postcode;
|
||||
$city = $this->shipping_city;
|
||||
|
||||
}
|
||||
|
||||
// Get items
|
||||
|
|
|
@ -953,10 +953,11 @@ class WC_Countries {
|
|||
if ( $type == 'billing_' ) {
|
||||
|
||||
$address_fields['billing_email'] = array(
|
||||
'label' => __( 'Email Address', 'woocommerce' ),
|
||||
'required' => true,
|
||||
'class' => array( 'form-row-first' ),
|
||||
'validate' => array( 'email' ),
|
||||
'label' => __( 'Email Address', 'woocommerce' ),
|
||||
'required' => true,
|
||||
'type' => 'email',
|
||||
'class' => array( 'form-row-first' ),
|
||||
'validate' => array( 'email' ),
|
||||
);
|
||||
|
||||
$address_fields['billing_phone'] = array(
|
||||
|
|
|
@ -121,10 +121,15 @@ class WC_Coupon {
|
|||
$this->code = apply_filters( 'woocommerce_coupon_code', $code );
|
||||
|
||||
// Coupon data lets developers create coupons through code
|
||||
if ( $coupon = apply_filters( 'woocommerce_get_shop_coupon_data', false, $code ) ) {
|
||||
if ( $coupon = apply_filters( 'woocommerce_get_shop_coupon_data', false, $this->code ) ) {
|
||||
$this->populate( $coupon );
|
||||
return true;
|
||||
} elseif ( ( $this->id = $this->get_coupon_id_from_code( $code ) ) && $this->code === apply_filters( 'woocommerce_coupon_code', get_the_title( $this->id ) ) ) {
|
||||
}
|
||||
|
||||
// Otherwise get ID from the code
|
||||
$this->id = $this->get_coupon_id_from_code( $this->code );
|
||||
|
||||
if ( $this->code === apply_filters( 'woocommerce_coupon_code', get_the_title( $this->id ) ) ) {
|
||||
$this->populate();
|
||||
return true;
|
||||
}
|
||||
|
@ -336,7 +341,7 @@ class WC_Coupon {
|
|||
* Ensure coupon amount is valid or throw exception
|
||||
*/
|
||||
private function validate_minimum_amount() {
|
||||
if ( $this->minimum_amount > 0 && $this->minimum_amount > WC()->cart->subtotal ) {
|
||||
if ( $this->minimum_amount > 0 && wc_format_decimal( $this->minimum_amount ) > wc_format_decimal( WC()->cart->subtotal ) ) {
|
||||
throw new Exception( self::E_WC_COUPON_MIN_SPEND_LIMIT_NOT_MET );
|
||||
}
|
||||
}
|
||||
|
@ -345,7 +350,7 @@ class WC_Coupon {
|
|||
* Ensure coupon amount is valid or throw exception
|
||||
*/
|
||||
private function validate_maximum_amount() {
|
||||
if ( $this->maximum_amount > 0 && $this->maximum_amount < WC()->cart->subtotal ) {
|
||||
if ( $this->maximum_amount > 0 && wc_format_decimal( $this->minimum_amount ) < wc_format_decimal( WC()->cart->subtotal ) ) {
|
||||
throw new Exception( self::E_WC_COUPON_MAX_SPEND_LIMIT_MET );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -568,6 +568,9 @@ function wc_delete_shop_order_transients( $post_id = 0 ) {
|
|||
delete_transient( $transient );
|
||||
}
|
||||
|
||||
// Increments the transient version to invalidate cache
|
||||
WC_Cache_Helper::get_transient_version( 'orders', true );
|
||||
|
||||
do_action( 'woocommerce_delete_shop_order_transients', $post_id );
|
||||
}
|
||||
|
||||
|
|
|
@ -198,23 +198,35 @@ function wc_get_featured_product_ids() {
|
|||
*/
|
||||
function wc_product_post_type_link( $permalink, $post ) {
|
||||
// Abort if post is not a product
|
||||
if ( $post->post_type !== 'product' )
|
||||
if ( $post->post_type !== 'product' ) {
|
||||
return $permalink;
|
||||
}
|
||||
|
||||
// Abort early if the placeholder rewrite tag isn't in the generated URL
|
||||
if ( false === strpos( $permalink, '%' ) )
|
||||
if ( false === strpos( $permalink, '%' ) ) {
|
||||
return $permalink;
|
||||
}
|
||||
|
||||
// Get the custom taxonomy terms in use by this post
|
||||
$terms = get_the_terms( $post->ID, 'product_cat' );
|
||||
|
||||
if ( empty( $terms ) ) {
|
||||
if ( ! empty( $terms ) ) {
|
||||
usort( $terms, '_usort_terms_by_ID' ); // order by ID
|
||||
|
||||
$category_object = apply_filters( 'wc_product_post_type_link_product_cat', $terms[0], $terms, $post );
|
||||
$category_object = get_term( $category_object, 'product_cat' );
|
||||
$product_cat = $category_object->slug;
|
||||
|
||||
if ( $parent = $category_object->parent ) {
|
||||
$ancestors = get_ancestors( $category_object->term_id, 'product_cat' );
|
||||
foreach ( $ancestors as $ancestor ) {
|
||||
$ancestor_object = get_term( $ancestor, 'product_cat' );
|
||||
$product_cat = $ancestor_object->slug . '/' . $product_cat;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If no terms are assigned to this post, use a string instead (can't leave the placeholder there)
|
||||
$product_cat = _x( 'uncategorized', 'slug', 'woocommerce' );
|
||||
} else {
|
||||
// Replace the placeholder rewrite tag with the first term's slug
|
||||
$first_term = array_shift( $terms );
|
||||
$product_cat = $first_term->slug;
|
||||
}
|
||||
|
||||
$find = array(
|
||||
|
@ -241,8 +253,6 @@ function wc_product_post_type_link( $permalink, $post ) {
|
|||
$product_cat
|
||||
);
|
||||
|
||||
$replace = array_map( 'sanitize_title', $replace );
|
||||
|
||||
$permalink = str_replace( $find, $replace, $permalink );
|
||||
|
||||
return $permalink;
|
||||
|
|
|
@ -1770,6 +1770,23 @@ if ( ! function_exists( 'woocommerce_form_field' ) ) {
|
|||
|
||||
$field .= '</p>' . $after;
|
||||
|
||||
break;
|
||||
case 'email' :
|
||||
|
||||
$field = '<p class="form-row ' . esc_attr( implode( ' ', $args['class'] ) ) .'" id="' . esc_attr( $args['id'] ) . '_field">';
|
||||
|
||||
if ( $args['label'] ) {
|
||||
$field .= '<label for="' . esc_attr( $args['id'] ) . '" class="' . esc_attr( implode( ' ', $args['label_class'] ) ) .'">' . $args['label'] . $required . '</label>';
|
||||
}
|
||||
|
||||
$field .= '<input type="email" class="input-text ' . esc_attr( implode( ' ', $args['input_class'] ) ) .'" name="' . esc_attr( $key ) . '" id="' . esc_attr( $args['id'] ) . '" placeholder="' . esc_attr( $args['placeholder'] ) . '" '.$args['maxlength'].' value="' . esc_attr( $value ) . '" ' . implode( ' ', $custom_attributes ) . ' />';
|
||||
|
||||
if ( $args['description'] ) {
|
||||
$field .= '<span class="description">' . esc_attr( $args['description'] ) . '</span>';
|
||||
}
|
||||
|
||||
$field .= '</p>' . $after;
|
||||
|
||||
break;
|
||||
case 'select' :
|
||||
|
||||
|
|
|
@ -210,7 +210,6 @@ add_action( 'woocommerce_order_status_completed', 'wc_paying_customer' );
|
|||
/**
|
||||
* Checks if a user (by email) has bought an item
|
||||
*
|
||||
* @access public
|
||||
* @param string $customer_email
|
||||
* @param int $user_id
|
||||
* @param int $product_id
|
||||
|
@ -219,46 +218,47 @@ add_action( 'woocommerce_order_status_completed', 'wc_paying_customer' );
|
|||
function wc_customer_bought_product( $customer_email, $user_id, $product_id ) {
|
||||
global $wpdb;
|
||||
|
||||
$emails = array();
|
||||
$transient_name = 'wc_cbp_' . md5( $customer_email . $user_id . $product_id . WC_Cache_Helper::get_transient_version( 'orders' ) );
|
||||
|
||||
if ( $user_id ) {
|
||||
$user = get_user_by( 'id', $user_id );
|
||||
if ( false === ( $result = get_transient( $transient_name ) ) ) {
|
||||
$customer_data = array( $user_id );
|
||||
|
||||
if ( isset( $user->user_email ) ) {
|
||||
$emails[] = $user->user_email;
|
||||
if ( $user_id ) {
|
||||
$user = get_user_by( 'id', $user_id );
|
||||
|
||||
if ( isset( $user->user_email ) ) {
|
||||
$customer_data[] = $user->user_email;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_email( $customer_email ) ) {
|
||||
$emails[] = $customer_email;
|
||||
}
|
||||
if ( is_email( $customer_email ) ) {
|
||||
$customer_data[] = $customer_email;
|
||||
}
|
||||
|
||||
if ( sizeof( $emails ) == 0 ) {
|
||||
return false;
|
||||
}
|
||||
$customer_data = array_filter( array_unique( $customer_data ) );
|
||||
|
||||
return $wpdb->get_var(
|
||||
$wpdb->prepare( "
|
||||
SELECT COUNT( DISTINCT order_items.order_item_id )
|
||||
FROM {$wpdb->prefix}woocommerce_order_items as order_items
|
||||
LEFT JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS itemmeta ON order_items.order_item_id = itemmeta.order_item_id
|
||||
LEFT JOIN {$wpdb->postmeta} AS postmeta ON order_items.order_id = postmeta.post_id
|
||||
LEFT JOIN {$wpdb->posts} AS posts ON order_items.order_id = posts.ID
|
||||
WHERE
|
||||
posts.post_status IN ( 'wc-completed', 'wc-processing' ) AND
|
||||
itemmeta.meta_value = %s AND
|
||||
itemmeta.meta_key IN ( '_variation_id', '_product_id' ) AND
|
||||
postmeta.meta_key IN ( '_billing_email', '_customer_user' ) AND
|
||||
(
|
||||
postmeta.meta_value IN ( '" . implode( "','", array_unique( $emails ) ) . "' ) OR
|
||||
(
|
||||
postmeta.meta_value = %s AND
|
||||
postmeta.meta_value > 0
|
||||
)
|
||||
)
|
||||
", $product_id, $user_id
|
||||
)
|
||||
);
|
||||
if ( sizeof( $customer_data ) == 0 ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$result = $wpdb->get_var(
|
||||
$wpdb->prepare( "
|
||||
SELECT 1 FROM {$wpdb->posts} AS p
|
||||
INNER JOIN {$wpdb->postmeta} AS pm ON p.ID = pm.post_id
|
||||
INNER JOIN {$wpdb->prefix}woocommerce_order_items AS i ON p.ID = i.order_id
|
||||
INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS im ON i.order_item_id = im.order_item_id
|
||||
WHERE p.post_status IN ( 'wc-completed', 'wc-processing' )
|
||||
AND pm.meta_key IN ( '_billing_email', '_customer_user' )
|
||||
AND pm.meta_value IN ( '" . implode( "','", $customer_data ) . "' )
|
||||
AND im.meta_key IN ( '_product_id', '_variation_id' )
|
||||
AND im.meta_value = %s
|
||||
", $product_id
|
||||
)
|
||||
);
|
||||
|
||||
set_transient( $transient_name, $result ? 1 : 0, DAY_IN_SECONDS * 30 );
|
||||
}
|
||||
return (bool) $result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -406,7 +406,7 @@ function wc_get_customer_available_downloads( $customer_id ) {
|
|||
", $customer_id, date( 'Y-m-d', current_time( 'timestamp' ) ) ) );
|
||||
|
||||
if ( $results ) {
|
||||
|
||||
|
||||
$looped_downloads = array();
|
||||
foreach ( $results as $result ) {
|
||||
if ( ! $order || $order->id != $result->order_id ) {
|
||||
|
@ -439,7 +439,7 @@ function wc_get_customer_available_downloads( $customer_id ) {
|
|||
}
|
||||
|
||||
$download_file = $_product->get_file( $result->download_id );
|
||||
|
||||
|
||||
// Check if the file has been already added to the downloads list
|
||||
if ( in_array( $download_file, $looped_downloads ) ) {
|
||||
continue;
|
||||
|
|
|
@ -138,6 +138,7 @@ Yes you can! Join in on our [GitHub repository](http://github.com/woothemes/wooc
|
|||
|
||||
== Changelog ==
|
||||
|
||||
* Feature - Show full category hierarchy in permalinks.
|
||||
* Fix - Ensure coupon taxes are reset when calculating totals.
|
||||
* Tweak - Base discounts on the undiscounted price. #5874
|
||||
|
||||
|
@ -159,7 +160,7 @@ Yes you can! Join in on our [GitHub repository](http://github.com/woothemes/wooc
|
|||
* Fix - Settings API - allow multiselect fields to be emptied.
|
||||
* Fix - Saving an order needs to save the discount amount ex. tax like the cart.
|
||||
* Fix - Order again with custom attributes.
|
||||
* Fix - Prevent potential XSS within tooltips (discovered by FortiGuard Labs).
|
||||
* Fix - [CVE-2015-2329] Prevent potential XSS within tooltips (discovered by Fortinet FortiGuard Labs).
|
||||
* Fix - Paypal debug option.
|
||||
* Fix - Removed $q->query['wc_query'] = 'product_query' which broke redirects (#7703). Use $q->get('wc_query') instead.
|
||||
* Fix - Sanitize tax_rate_id when saving taxes in the backend to prevent potential SQL injection (discovered by WordFence).
|
||||
|
|
|
@ -26,7 +26,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||
</tr>
|
||||
|
||||
<?php foreach ( WC()->cart->get_coupons() as $code => $coupon ) : ?>
|
||||
<tr class="cart-discount coupon-<?php echo esc_attr( $code ); ?>">
|
||||
<tr class="cart-discount coupon-<?php echo esc_attr( sanitize_title( $code ) ); ?>">
|
||||
<th><?php wc_cart_totals_coupon_label( $coupon ); ?></th>
|
||||
<td><?php wc_cart_totals_coupon_html( $coupon ); ?></td>
|
||||
</tr>
|
||||
|
|
|
@ -52,7 +52,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
|||
</tr>
|
||||
|
||||
<?php foreach ( WC()->cart->get_coupons() as $code => $coupon ) : ?>
|
||||
<tr class="cart-discount coupon-<?php echo esc_attr( $code ); ?>">
|
||||
<tr class="cart-discount coupon-<?php echo esc_attr( sanitize_title( $code ) ); ?>">
|
||||
<th><?php wc_cart_totals_coupon_label( $coupon ); ?></th>
|
||||
<td><?php wc_cart_totals_coupon_html( $coupon ); ?></td>
|
||||
</tr>
|
||||
|
|
|
@ -17,7 +17,7 @@ foreach ( $items as $item_id => $item ) :
|
|||
|
||||
if ( apply_filters( 'woocommerce_order_item_visible', true, $item ) ) {
|
||||
?>
|
||||
<tr>
|
||||
<tr class="<?php echo esc_attr( apply_filters( 'woocoomerce_order_item_class', 'order_item', $item, $order ) ); ?>">
|
||||
<td style="text-align:left; vertical-align:middle; border: 1px solid #eee; word-wrap:break-word;"><?php
|
||||
|
||||
// Show title/image etc
|
||||
|
|
Loading…
Reference in New Issue