Automattic\WooCommerce\Internal\StockNotifications\Frontend

SignupService::signup │ public │ WC 1.0

Signup.

Fail-closed: once the rate limit window is claimed it is not released, so a failure or an exception raised further down still holds the customer back until the window expires. A window that cannot be claimed at all is the exception, and lets the sign-up through.

Method of the class: SignupService{}

Returns

SignupResult|\WP_Error. The signup result.

Usage

$SignupService = new SignupService();
$SignupService->signup( $product_id, $user_id, $user_email, $posted_attributes );
$product_id(int) (required)
The product ID.
$user_id(int) (required)
The user ID.
$user_email(string) (required)
The user email.
$posted_attributes(array)
The posted attributes (Optional).
Default: array()

SignupService::signup() code WC 11.2.1

public function signup( int $product_id, int $user_id, string $user_email, array $posted_attributes = array() ) {

	$user_email = EmailNormalizer::normalize( $user_email );

	// Sanity checks.
	if ( ! Config::allows_signups() ) {
		return new \WP_Error( self::ERROR_FAILED );
	}

	if ( empty( $user_email ) && empty( $user_id ) ) {
		return new \WP_Error( self::ERROR_INVALID_REQUEST );
	}

	$product = wc_get_product( $product_id );
	if ( ! $product ) {
		return new \WP_Error( self::ERROR_INVALID_PRODUCT );
	}

	if ( ! $this->eligibility_service->is_product_eligible( $product ) ) {
		return new \WP_Error( self::ERROR_INVALID_PRODUCT );
	}

	if ( $this->eligibility_service->is_stock_status_eligible( $product->get_stock_status() ) ) {
		return new \WP_Error( self::ERROR_INVALID_REQUEST );
	}

	if ( ! $this->eligibility_service->product_allows_signups( $product ) ) {
		return new \WP_Error( self::ERROR_INVALID_PRODUCT );
	}

	// Attempts that only find an existing active or pending sign-up, or activate an existing
	// pending one, create nothing new and send no verification mail, so they are answered
	// before the rate limit is consulted or claimed.
	$notification = $this->is_already_signed_up( $product_id, $user_id, $user_email, $posted_attributes );
	if ( $notification instanceof Notification ) {
		if ( NotificationStatus::ACTIVE === $notification->get_status() ) {
			return new SignupResult( self::SIGNUP_ALREADY_JOINED, $notification );
		}

		if ( NotificationStatus::PENDING === $notification->get_status() ) {
			if ( Config::requires_double_opt_in() ) {
				return new SignupResult( self::SIGNUP_ALREADY_JOINED_DOUBLE_OPT_IN, $notification );
			}

			// Double opt-in is not required, so activate the pending notification instead of creating one.
			$notification->set_status( NotificationStatus::ACTIVE );
			$saved = $notification->save();
			if ( \is_wp_error( $saved ) || ! $saved ) {
				return new \WP_Error( self::ERROR_FAILED );
			}

			/**
			 * Action: woocommerce_customer_stock_notifications_signup
			 *
			 * @since 10.2.0
			 *
			 * @param Notification $notification The notification.
			 */
			do_action( 'woocommerce_customer_stock_notifications_signup', $notification );
			return new SignupResult( self::SIGNUP_SUCCESS, $notification );
		}
	}

	if ( SignupRateLimiter::is_rate_limited( $user_email ) ) {
		return new \WP_Error( self::ERROR_RATE_LIMITED );
	}

	// Claim the rate limit window before storing a notification or sending mail. This
	// narrows the window in which two near-simultaneous requests both get through; it
	// does not close it.
	//
	// A claim only fails when the rate limit table cannot be written to, which a shopper
	// can neither cause nor resolve. Let the sign-up through rather than turn a broken
	// limiter into a store-wide sign-up outage.
	if ( ! SignupRateLimiter::apply( $user_email ) ) {
		$this->logger->warning(
			'Could not claim the stock notification sign-up rate limit window. Allowing the sign-up to proceed.',
			array( 'source' => 'stock-notifications-signup-errors' )
		);
	}

	$notification = new Notification();
	$notification->set_status( NotificationStatus::ACTIVE );
	$notification->set_product_id( $product_id );
	$notification->set_user_id( $user_id );
	$notification->set_user_email( $user_email );

	if ( ! empty( $posted_attributes ) ) {
		$notification->update_meta_data( 'posted_attributes', $posted_attributes );
	}

	if ( Config::requires_double_opt_in() ) {
		$notification->set_status( NotificationStatus::PENDING );
	}

	$saved = $notification->save();
	if ( \is_wp_error( $saved ) || ! $saved ) {
		return new \WP_Error( self::ERROR_FAILED );
	}

	/**
	 * Action: woocommerce_customer_stock_notifications_signup
	 *
	 * @since 10.2.0
	 *
	 * @param Notification $notification The notification.
	 */
	do_action( 'woocommerce_customer_stock_notifications_signup', $notification );

	if ( Config::requires_double_opt_in() && NotificationStatus::PENDING === $notification->get_status() ) {
		$this->email_manager->send_verify_email( $notification );
	}

	$signup_code = Config::requires_double_opt_in() ? self::SIGNUP_SUCCESS_DOUBLE_OPT_IN : self::SIGNUP_SUCCESS;
	return new SignupResult( $signup_code, $notification );
}