$field['discountType'] ?? 'fixed', 'value' => (float) ( $field['discountValue'] ?? 0 ), ]; } } $tax_total = 0.0; foreach ( $tax_rates as $rate ) { $tax_total += $subtotal * ( $rate / 100 ); } $discount_total = 0.0; foreach ( $discounts as $discount ) { $discount_total += 'percent' === $discount['type'] ? $subtotal * ( $discount['value'] / 100 ) : $discount['value']; } return [ 'subtotal' => $subtotal, 'shipping' => $shipping, 'tax_rates' => $tax_rates, 'discounts' => $discounts, 'total' => max( 0, $subtotal + $shipping + $tax_total - $discount_total ), ]; } /** * The one place that walks a form's field tree looking for its Payment * Method field — shared by RestApi::create_subscription() (needs the * field's billingType/billingInterval/trialDays config before starting * a subscription) and SubmissionHandler (needs the same config to know * which verify_*() path to take). Recursive, unlike the private, * top-level-only version SubmissionHandler had before this — a Payment * Method field nested inside a Section/Row/Column previously would * silently never be found by that check; this fixes that as a side * effect of not duplicating the walk a second time, not as a separate * change. Returns the first payment_method field found, or null. */ public static function find_payment_method_field( array $fields ) { foreach ( $fields as $field ) { if ( 'payment_method' === ( $field['type'] ?? '' ) ) { return $field; } if ( ! empty( $field['children'] ) && is_array( $field['children'] ) ) { $found = self::find_payment_method_field( $field['children'] ); if ( $found ) { return $found; } } } return null; } }