cart; if ( ! $cart || ! $cart->needs_shipping() ) { return null; } $target = $this->threshold( $cart ); if ( null === $target ) { return null; } list( $threshold, $ignore_discounts ) = $target; $current = $this->current_amount( $cart, $ignore_discounts ); $remaining = max( 0.0, $threshold - $current ); $reached = $remaining <= 0; if ( $reached && empty( $this->settings->get()['free_shipping_bar']['show_when_reached'] ) ) { return null; } $message = $reached ? __( 'You have unlocked free shipping!', 'extrova' ) : sprintf( /* translators: %s: amount left to reach free shipping. */ __( 'Add %s more to get free shipping.', 'extrova' ), Money::plain( $remaining ) ); return array( 'threshold' => Money::decimal( $threshold ), 'current' => Money::decimal( min( $current, $threshold ) ), 'remaining' => Money::decimal( $remaining ), 'reached' => $reached, 'message' => $message, ); } /** * Lowest free shipping minimum in the first package's zone. * * @param \WC_Cart $cart Cart. * @return array{0: float, 1: bool}|null [ threshold, ignore_discounts ]. */ private function threshold( \WC_Cart $cart ): ?array { $packages = $cart->get_shipping_packages(); $package = is_array( $packages ) ? reset( $packages ) : false; if ( ! is_array( $package ) ) { return null; } $zone = \WC_Shipping_Zones::get_zone_matching_package( $package ); $result = null; foreach ( $zone->get_shipping_methods( true ) as $method ) { if ( ! $method instanceof \WC_Shipping_Free_Shipping ) { continue; } $requires = (string) $method->get_option( 'requires', '' ); if ( ! in_array( $requires, array( 'min_amount', 'either', 'both' ), true ) ) { continue; } $min = (float) wc_format_decimal( (string) $method->get_option( 'min_amount', '0' ) ); if ( $min <= 0 ) { continue; } if ( null === $result || $min < $result[0] ) { $result = array( $min, 'yes' === $method->get_option( 'ignore_discounts', 'no' ) ); } } return $result; } /** * Amount counted towards the threshold (mirrors WC_Shipping_Free_Shipping). * * @param \WC_Cart $cart Cart. * @param bool $ignore_discounts Whether coupons are ignored. */ private function current_amount( \WC_Cart $cart, bool $ignore_discounts ): float { $total = (float) $cart->get_displayed_subtotal(); if ( $cart->display_prices_including_tax() ) { $total -= (float) $cart->get_discount_tax(); } if ( ! $ignore_discounts ) { $total -= (float) $cart->get_discount_total(); } return round( $total, wc_get_price_decimals() ); } }