WC_Coupon_Data_Store_CPT::check_and_hold_coupon()publicWC 1.0

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.

Method of the class: WC_Coupon_Data_Store_CPT{}

Hooks from the method

Return

true|false|Int|String|null. Returns meta key if coupon was held, null if returned early.

Usage

$WC_Coupon_Data_Store_CPT = new WC_Coupon_Data_Store_CPT();
$WC_Coupon_Data_Store_CPT->check_and_hold_coupon( $coupon );
$coupon(WC_Coupon) (required)
Coupon object.

WC_Coupon_Data_Store_CPT::check_and_hold_coupon() code WC 9.4.2

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 ' . $wpdb->posts . ' LIMIT 1' );

	$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 $wpdb->posts
		WHERE ( $query_for_usages ) + ( $query_for_tentative_usages ) < %d
		LIMIT 1",
		$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 ) {
			// Clear meta cache.
			$this->refresh_coupon_data( $coupon );
			break;
		}
	}

	return $result > 0 ? $coupon_usage_key : $result;
}