Merge pull request #8940 from woothemes/issues/8482

Tidy up how we're dealing with coupon postmeta around `_used_by` which can get big.
This commit is contained in:
Mike Jolley 2015-09-15 16:42:51 +01:00
commit 3e55364e3a
2 changed files with 45 additions and 10 deletions

View File

@ -1615,7 +1615,7 @@ class WC_Cart {
// Usage limits per user - check against billing and user email and user ID
if ( $coupon->usage_limit_per_user > 0 ) {
$check_emails = array();
$used_by = array_filter( (array) get_post_meta( $coupon->id, '_used_by' ) );
$used_by = $coupon->get_used_by();
if ( is_user_logged_in() ) {
$current_user = wp_get_current_user();

View File

@ -172,10 +172,19 @@ class WC_Coupon {
'customer_email' => array()
);
if ( ! empty( $this->id ) ) {
$postmeta = get_post_meta( $this->id );
}
foreach ( $defaults as $key => $value ) {
// Try to load from meta if an ID is present
if ( $this->id ) {
$this->$key = get_post_meta( $this->id, $key, true );
if ( ! empty( $this->id ) ) {
/**
* By not calling `get_post_meta()` individually, we may be breaking compatibility with
* some plugins that filter on `get_post_metadata` and erroneously override based solely
* on $meta_key -- but don't override when querying for all as $meta_key is empty().
*/
$this->$key = isset( $postmeta[ $key ] ) ? maybe_unserialize( array_shift( $postmeta[ $key ] ) ) : '';
} else {
$this->$key = ! empty( $data[ $key ] ) ? wc_clean( $data[ $key ] ) : '';
@ -271,14 +280,31 @@ class WC_Coupon {
$this->usage_count--;
update_post_meta( $this->id, 'usage_count', $this->usage_count );
// Delete 1 used by meta
$meta_id = $wpdb->get_var( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE meta_key = '_used_by' AND meta_value = %s AND post_id = %d LIMIT 1;", $used_by, $this->id ) );
if ( $meta_id ) {
delete_metadata_by_mid( 'post', $meta_id );
if ( $used_by ) {
/**
* We're doing this the long way because `delete_post_meta( $id, $key, $value )` deletes
* all instances where the key and value match, and we only want to delete one.
*/
$meta_id = $wpdb->get_var( $wpdb->prepare( "SELECT meta_id FROM $wpdb->postmeta WHERE meta_key = '_used_by' AND meta_value = %s AND post_id = %d LIMIT 1;", $used_by, $this->id ) );
if ( $meta_id ) {
delete_metadata_by_mid( 'post', $meta_id );
}
}
}
}
/**
* Get records of all users who have used the current coupon.
*
* @access public
* @return array
*/
public function get_used_by() {
$_used_by = (array) get_post_meta( $this->id, '_used_by' );
// Strip out any null values.
return array_filter( $_used_by );
}
/**
* Returns the error_message string
*
@ -312,11 +338,20 @@ class WC_Coupon {
*
* Per user usage limit - check here if user is logged in (against user IDs)
* Checked again for emails later on in WC_Cart::check_customer_coupons()
*
* @param int $user_id
*/
private function validate_user_usage_limit() {
private function validate_user_usage_limit( $user_id = null ) {
if ( ! $user_id ) {
$user_id = get_current_user_id();
}
if ( $this->usage_limit_per_user > 0 && is_user_logged_in() && $this->id ) {
$used_by = (array) get_post_meta( $this->id, '_used_by' );
$usage_count = sizeof( array_keys( $used_by, get_current_user_id() ) );
global $wpdb;
$wpdb->get_var( $wpdb->prepare( "SELECT COUNT( `meta_id` )
FROM {$wpdb->postmeta}
WHERE `post_id` = %d
AND `meta_key` = '_used_by'
AND `meta_value` = %d", $this->id, $user_id ) );
if ( $usage_count >= $this->usage_limit_per_user ) {
throw new Exception( self::E_WC_COUPON_USAGE_LIMIT_REACHED );