Automattic\WooCommerce\StoreApi\Routes\V1
Checkout::validate_order_totals
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.
Method of the class: Checkout{}
No Hooks.
Returns
null. Nothing (null).
Usage
// private - for code of main (parent) class only $result = $this->validate_order_totals( $request ): void;
- $request(WP_REST_Request) (required)
- Request object.
Checkout::validate_order_totals() Checkout::validate order totals code WC 11.1.2
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 ),
]
);
}