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.


Top ↑

Return Return

(bool|int|string|null) Returns meta key if coupon was held, null if returned early.


Top ↑

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;
	}


Top ↑

User Contributed Notes User Contributed Notes

You must log in before being able to contribute a note or feedback.