Files
2026-04-28 15:13:50 +02:00

178 lines
6.6 KiB
PHP

<?php
/**
* Class WooCommerceBookings
*
* @package WCPay\MultiCurrency\Compatibility
*/
namespace WCPay\MultiCurrency\Compatibility;
use WCPay\MultiCurrency\FrontendCurrencies;
use WCPay\MultiCurrency\MultiCurrency;
use WCPay\MultiCurrency\Utils;
use WC_Product;
/**
* Class that controls Multi Currency Compatibility with WooCommerce Bookings Plugin.
*/
class WooCommerceBookings extends BaseCompatibility {
/**
* Front-end currencies.
*
* @var FrontendCurrencies
*/
private $frontend_currencies;
/**
* Constructor.
*
* @param MultiCurrency $multi_currency MultiCurrency class.
* @param Utils $utils Utils class.
* @param FrontendCurrencies $frontend_currencies FrontendCurrencies class.
*/
public function __construct( MultiCurrency $multi_currency, Utils $utils, FrontendCurrencies $frontend_currencies ) {
parent::__construct( $multi_currency, $utils );
$this->frontend_currencies = $frontend_currencies;
}
/**
* Init the class.
*
* @return void
*/
public function init() {
// Add needed actions and filters if Bookings is active.
if ( class_exists( 'WC_Bookings' ) ) {
if ( ! is_admin() || wp_doing_ajax() ) {
add_filter( 'woocommerce_bookings_calculated_booking_cost', [ $this, 'adjust_amount_for_calculated_booking_cost' ], 50, 1 );
add_filter( 'woocommerce_product_get_block_cost', [ $this, 'get_price' ], 50, 1 );
add_filter( 'woocommerce_product_get_cost', [ $this, 'get_price' ], 50, 1 );
add_filter( 'woocommerce_product_get_display_cost', [ $this, 'get_price' ], 50, 1 );
add_filter( 'woocommerce_product_booking_person_type_get_block_cost', [ $this, 'get_price' ], 50, 1 );
add_filter( 'woocommerce_product_booking_person_type_get_cost', [ $this, 'get_price' ], 50, 1 );
add_filter( 'woocommerce_product_get_resource_base_costs', [ $this, 'get_resource_prices' ], 50, 1 );
add_filter( 'woocommerce_product_get_resource_block_costs', [ $this, 'get_resource_prices' ], 50, 1 );
add_filter( MultiCurrency::FILTER_PREFIX . 'should_convert_product_price', [ $this, 'should_convert_product_price' ], 50, 2 );
add_filter( 'woocommerce_bookings_process_cost_rules_cost', [ $this, 'get_price' ], 50, 1 );
add_filter( 'woocommerce_bookings_process_cost_rules_base_cost', [ $this, 'get_price' ], 50, 1 );
add_action( 'wp_ajax_wc_bookings_calculate_costs', [ $this, 'add_wc_price_args_filter_for_ajax' ], 9 );
add_action( 'wp_ajax_nopriv_wc_bookings_calculate_costs', [ $this, 'add_wc_price_args_filter_for_ajax' ], 9 );
}
}
}
/**
* Adjusts the calculated booking cost for the selected currency, applying rounding and charm pricing as necessary.
*
* @param mixed $costs The original calculated booking costs.
* @return mixed The booking cost adjusted for the selected currency.
*/
public function adjust_amount_for_calculated_booking_cost( $costs ) {
/**
* Prevents adjustment of the calculated booking cost during cart addition.
*
* When a booking is added to the cart, the Booking plugin calculates the booking cost and
* overrides the cart item price with this calculated amount. To avoid interfering with this process,
* this function skips any additional adjustments at this stage.
*/
if ( $this->utils->is_call_in_backtrace( [ 'WC_Cart->add_to_cart' ] ) ) {
return $costs;
}
return $this->multi_currency->adjust_amount_for_selected_currency( $costs );
}
/**
* Retrieves the price for an item, converting it based on the selected currency and context.
*
* @param mixed $price The item's price.
*
* @return mixed The converted item's price.
*/
public function get_price( $price ) {
if ( ! $price ) {
return $price;
}
// Skip conversion during specific booking cost calculations to avoid double conversion.
if ( $this->utils->is_call_in_backtrace( [ 'WC_Cart->add_to_cart' ] ) && $this->utils->is_call_in_backtrace( [ 'WC_Bookings_Cost_Calculation::calculate_booking_cost' ] ) ) {
return $price;
}
/**
* When showing the price in HTML, the function applies currency conversion, charm pricing,
* and rounding. For internal calculations, it uses the raw exchange rate, with charm pricing
* and rounding adjustments applied only to the final calculated amount (handled in
* adjust_amount_for_calculated_booking_cost).
*/
return $this->multi_currency->get_price( $price, $this->utils->is_call_in_backtrace( [ 'WC_Product_Booking->get_price_html' ] ) ? 'product' : 'exchange_rate' );
}
/**
* Returns the prices for a resource.
*
* @param mixed $prices The resource's prices in array format.
*
* @return mixed The converted resource's prices.
*/
public function get_resource_prices( $prices ) {
if ( is_array( $prices ) ) {
foreach ( $prices as $key => $price ) {
$prices[ $key ] = $this->get_price( $price );
}
}
return $prices;
}
/**
* Checks to see if the product's price should be converted.
*
* @param bool $return Whether to convert the product's price or not. Default is true.
* @param WC_Product $product The product instance being checked.
*
* @return bool True if it should be converted.
*/
public function should_convert_product_price( bool $return, WC_Product $product ): bool {
// If it's already false, or the product is not a booking, ignore it.
if ( ! $return || $product->get_type() !== 'booking' ) {
return $return;
}
// Fixes price display on product page and in shop.
if ( $this->utils->is_call_in_backtrace( [ 'WC_Product_Booking->get_price_html' ] ) ) {
return false;
}
return $return;
}
/**
* Adds a filter for when there is an ajax call to calculate the booking cost.
*
* @return void
*/
public function add_wc_price_args_filter_for_ajax() {
add_filter( 'wc_price_args', [ $this, 'filter_wc_price_args' ], 100 );
}
/**
* Returns the formatting arguments to use when a booking price is calculated on the product.
*
* @param array $args Original args from wc_price().
*
* @return array New arguments matching the selected currency.
*/
public function filter_wc_price_args( $args ): array {
return wp_parse_args(
[
'currency' => $this->multi_currency->get_selected_currency()->get_code(),
'decimal_separator' => $this->frontend_currencies->get_price_decimal_separator( $args['decimal_separator'] ),
'thousand_separator' => $this->frontend_currencies->get_price_thousand_separator( $args['thousand_separator'] ),
'decimals' => $this->frontend_currencies->get_price_decimals( $args['decimals'] ),
'price_format' => $this->frontend_currencies->get_woocommerce_price_format( $args['price_format'] ),
],
$args
);
}
}