$attributes */ public static function build( int $product_id, int $quantity = 1, int $variation_id = 0, array $attributes = [], int $order_bump_id = 0 ): string { if ( $product_id <= 0 ) { return ''; } ksort( $attributes ); return hash( 'sha256', wp_json_encode( [ 'product_id' => $product_id, 'quantity' => max( 1, $quantity ), 'variation_id' => max( 0, $variation_id ), 'attributes' => $attributes, 'order_bump_id' => max( 0, $order_bump_id ), ] ) ); } public static function build_from_request(): string { $product_id = AddToCartContext::get_requested_product_id(); if ( $product_id <= 0 ) { return ''; } if ( ! is_scalar( $_REQUEST['quantity'] ?? 1 ) ) { return ''; } $quantity = wc_stock_amount( wp_unslash( $_REQUEST['quantity'] ?? 1 ) ); $variation_id = is_scalar( $_REQUEST['variation_id'] ?? null ) ? absint( wp_unslash( $_REQUEST['variation_id'] ) ) : 0; $order_bump_id = is_scalar( $_REQUEST['ips_order_bump_id'] ?? null ) ? absint( wp_unslash( $_REQUEST['ips_order_bump_id'] ) ) : 0; return self::build( $product_id, (int) $quantity, $variation_id, self::extract_attributes_from_request(), $order_bump_id ); } /** * @param array $variation_attributes */ public static function has_recent_match( int $product_id, int $quantity = 1, int $variation_id = 0, array $variation_attributes = [], int $order_bump_id = 0 ): bool { $fingerprint = self::build( $product_id, $quantity, $variation_id, $variation_attributes, $order_bump_id ); if ( '' === $fingerprint ) { return false; } $fingerprints = self::get_recent_fingerprints(); return isset( $fingerprints[ $fingerprint ] ) && ( time() - (int) $fingerprints[ $fingerprint ] ) <= self::TTL_SECONDS; } public static function remember_request( string $fingerprint ): void { if ( '' === $fingerprint ) { return; } $fingerprints = self::get_recent_fingerprints(); $fingerprints[ $fingerprint ] = time(); self::set_recent_fingerprints( $fingerprints ); } public static function has_recent_fingerprint( string $fingerprint ): bool { if ( '' === $fingerprint ) { return false; } $fingerprints = self::get_recent_fingerprints(); return isset( $fingerprints[ $fingerprint ] ) && ( time() - (int) $fingerprints[ $fingerprint ] ) <= self::TTL_SECONDS; } /** * @return array */ private static function get_recent_fingerprints(): array { if ( ! function_exists( 'WC' ) || ! WC()->session ) { return []; } $stored = WC()->session->get( self::SESSION_KEY, [] ); if ( ! is_array( $stored ) ) { $stored = []; } $cutoff = time() - self::TTL_SECONDS; return array_filter( $stored, static function ( $timestamp ) use ( $cutoff ) { return is_numeric( $timestamp ) && (int) $timestamp >= $cutoff; } ); } /** * @param array $fingerprints */ private static function set_recent_fingerprints( array $fingerprints ): void { if ( ! function_exists( 'WC' ) || ! WC()->session ) { return; } WC()->session->set( self::SESSION_KEY, $fingerprints ); } /** * @return array */ private static function extract_attributes_from_request(): array { $attributes = []; foreach ( $_REQUEST as $key => $value ) { $attribute_key = sanitize_text_field( (string) $key ); if ( 0 !== strpos( $attribute_key, 'attribute_' ) || ! is_scalar( $value ) ) { continue; } $attributes[ $attribute_key ] = sanitize_title( (string) wp_unslash( $value ) ); } return $attributes; } }