WC_Coupon_Data_Store_CPT::check_and_hold_coupon( WC_Coupon $coupon )
Check and records coupon usage tentatively for short period of time so that counts validation is correct. Returns early if there is no limit defined for the coupon.
Description Description
Parameters Parameters
- $coupon
-
(Required) Coupon object.
Return Return
(bool|int|string|null) Returns meta key if coupon was held, null if returned early.
Source Source
File: includes/data-stores/class-wc-coupon-data-store-cpt.php
public function check_and_hold_coupon( $coupon ) { global $wpdb; $usage_limit = $coupon->get_usage_limit(); $held_time = $this->get_tentative_held_time(); if ( 0 >= $usage_limit || 0 >= $held_time ) { return null; } if ( ! apply_filters( 'woocommerce_hold_stock_for_checkout', true ) ) { return null; } // Make sure we have usage_count meta key for this coupon because its required for `$query_for_usages`. // We are not directly modifying `$query_for_usages` to allow for `usage_count` not present only keep that query simple. if ( ! metadata_exists( 'post', $coupon->get_id(), 'usage_count' ) ) { $coupon->set_usage_count( $coupon->get_usage_count() ); // Use `get_usage_count` here to write default value, which may changed by a filter. $coupon->save(); } $query_for_usages = $wpdb->prepare( " SELECT meta_value from $wpdb->postmeta WHERE {$wpdb->postmeta}.meta_key = 'usage_count' AND {$wpdb->postmeta}.post_id = %d LIMIT 1 FOR UPDATE ", $coupon->get_id() ); $query_for_tentative_usages = $this->get_tentative_usage_query( $coupon->get_id() ); $db_timestamp = $wpdb->get_var( 'SELECT UNIX_TIMESTAMP() FROM DUAL' ); $coupon_usage_key = '_coupon_held_' . ( (int) $db_timestamp + $held_time ) . '_' . wp_generate_password( 6, false ); $insert_statement = $wpdb->prepare( " INSERT INTO $wpdb->postmeta ( post_id, meta_key, meta_value ) SELECT %d, %s, %s FROM DUAL WHERE ( $query_for_usages ) + ( $query_for_tentative_usages ) < %d ", $coupon->get_id(), $coupon_usage_key, '', $usage_limit ); // WPCS: unprepared SQL ok. /** * In some cases, specifically when there is a combined index on post_id,meta_key, the insert statement above could end up in a deadlock. * We will try to insert 3 times before giving up to recover from deadlock. */ for ( $count = 0; $count < 3; $count++ ) { $result = $wpdb->query( $insert_statement ); // WPCS: unprepared SQL ok. if ( false !== $result ) { break; } } return $result > 0 ? $coupon_usage_key : $result; }