$customer_id->get_error_message() ), 400 ); } // Associate customer with the order. $order->set_customer_id( $customer_id ); // Set the customer auth cookie. wc_set_customer_auth_cookie( $customer_id ); wc_log_order_step( '[Store API #6::process_customer] Created new customer', array( 'customer_id' => $customer_id ) ); } // Persist customer address data to account. $this->order_controller->sync_customer_data_with_order( $order ); wc_log_order_step( '[Store API #6::process_customer] Synced customer data from order', array( 'customer_id' => $order->get_customer_id() ) ); } /** * Check request options and store (shop) config to determine if a user account should be created as part of order * processing. * * @param \WP_REST_Request $request The current request object being handled. * @return boolean True if a new user account should be created. */ private function should_create_customer_account( \WP_REST_Request $request ) { if ( is_user_logged_in() ) { return false; } // Return false if registration is not enabled for the store. if ( false === filter_var( WC()->checkout()->is_registration_enabled(), FILTER_VALIDATE_BOOLEAN ) ) { return false; } // Return true if the store requires an account for all purchases. Note - checkbox is not displayed to shopper in this case. if ( true === filter_var( WC()->checkout()->is_registration_required(), FILTER_VALIDATE_BOOLEAN ) ) { return true; } // Create an account if requested via the endpoint. if ( true === filter_var( $request['create_account'], FILTER_VALIDATE_BOOLEAN ) ) { // User has requested an account as part of checkout processing. return true; } return false; } /** * Reject the order if what the customer is going to be charged at is higher from what they saw. * * Runs on POST /checkout only, before the draft order is materialised, so a mismatch leaves * no order behind. The check only runs when the client sends the total it displayed; flows * that cannot know the final total up front (e.g. some express payment methods) omit it and * are unaffected. * * @phpstan-param \WP_REST_Request> $request * * @param \WP_REST_Request $request Request object. * @throws RouteException When the recalculated total is higher. Returns HTTP 409 with the refreshed cart so the client can display the updated total. */ private function validate_order_totals( \WP_REST_Request $request ): void { // The route schema constrains this to minor-unit digits, so the integer comparison below is exact. $expected_total = (string) ( $request['expected_total'] ?? '' ); if ( '' === $expected_total ) { return; } // CartSchema::prepare_money_response() is not exported, so we use the money formatter directly here to match the total_price format. $decimals = wc_get_price_decimals(); $actual_total = woocommerce_store_api_get_formatter( 'money' )->format( $this->cart_controller->get_cart_instance()->get_total( 'edit' ), [ 'decimals' => $decimals ] ); if ( (int) $actual_total <= (int) $expected_total ) { return; } $expected_amount = wc_remove_number_precision( absint( $expected_total ) ); $actual_amount = wc_remove_number_precision( absint( $actual_total ) ); throw new RouteException( 'woocommerce_rest_checkout_total_mismatch', sprintf( /* translators: %1$s: total the shopper confirmed, %2$s: updated, higher total */ esc_html__( 'The order total changed from %1$s to %2$s while you were checking out. Please review the updated total and place your order again.', 'woocommerce' ), esc_html( wc_price( $expected_amount, [ 'in_span' => false ] ) ), esc_html( wc_price( $actual_amount, [ 'in_span' => false ] ) ) ), 409, [ 'expected_total' => absint( $expected_total ), 'actual_total' => absint( $actual_total ), ] ); } /** * This validates if the order can be placed regarding settings in WooCommerce > Settings > Accounts & Privacy * If registration during checkout is disabled, guest checkout is disabled and the user is not logged in, prevent checkout. * * @throws RouteException If user cannot place order. */ private function validate_user_can_place_order() { if ( // "woocommerce_enable_signup_and_login_from_checkout" === no. false === filter_var( WC()->checkout()->is_registration_enabled(), FILTER_VALIDATE_BOOLEAN ) && // "woocommerce_enable_guest_checkout" === no. true === filter_var( WC()->checkout()->is_registration_required(), FILTER_VALIDATE_BOOLEAN ) && ! is_user_logged_in() ) { throw new RouteException( 'woocommerce_rest_guest_checkout_disabled', esc_html( /** * Filter to customize the checkout message when a user must be logged in. * * @since 9.4.3 * * @param string $message Message to display when a user must be logged in to check out. */ apply_filters( 'woocommerce_checkout_must_be_logged_in_message', __( 'You must be logged in to checkout.', 'woocommerce' ) ) ), 403 ); } } }