* @link http://domain.tld * @license GPL 2.0+ * @copyright 2022 WebAppick */ // Ensure the file is not accessed directly. if ( ! defined( 'ABSPATH' ) ) { exit; } use Disco\App\Disco; use Disco\App\Utility\Settings; if ( !function_exists( 'disco_get_discounted_price' ) ) { /** * Get the discounted price of a product. * * @param float $price Product Price. * @param \WC_Product $product Product Object. * @return float */ function disco_get_discounted_price( $price, $product ) { if ( is_admin() && ! defined( 'DOING_AJAX' ) ) { return $price; // Return original price in admin area. } return ( new Disco )->get_product_discounted_price( $price, $product ); } } if ( ! function_exists( 'disco_init_price_cache' ) ) { /** * Initialize the global price cache. * * @return void */ function disco_init_price_cache() { global $disco_price_cache; if ( ! isset( $disco_price_cache ) ) { $disco_price_cache = []; } } // Initialize cache on load disco_init_price_cache(); } if ( ! function_exists( 'disco_should_cache_price' ) ) { /** * Check if current page should use price cache. * Don't cache on checkout/cart/thankyou where user limits may change. * * @return bool */ function disco_should_cache_price() { // Allow filter to force disable cache (useful for tests) if ( apply_filters( 'disco_disable_price_cache', false ) ) { return false; } // Don't cache during AJAX (cart updates, checkout, etc.) if ( wp_doing_ajax() ) { return false; } // Don't cache on checkout or cart pages if ( function_exists( 'is_checkout' ) && is_checkout() ) { return false; } if ( function_exists( 'is_cart' ) && is_cart() ) { return false; } // Cache on shop, category, product pages return true; } } if ( ! function_exists( 'disco_clear_price_cache' ) ) { /** * Clear the discounted price cache. * * @return void */ function disco_clear_price_cache() { global $disco_price_cache; $disco_price_cache = []; } } if ( ! function_exists( 'disco_discounted_price' ) ) { /** * Applies discounted price logic to product prices (simple + variation). * * @param float $price Product Price. * @param \WC_Product $product Product Object. * @return float */ function disco_discounted_price( $price, $product ) { global $disco_price_cache; static $running = false; if ( $running || ! is_object( $product ) || ! $price ) { return $price; } $product_id = $product->get_id(); // Allow external code to exclude a product from Disco discounts. if ( apply_filters( 'disco_exclude_product_from_discount', false, $product_id, $product ) ) { return $price; } $cache_key = $product_id . '_' . $price; // Use cache only on safe pages (shop, category, product) if ( disco_should_cache_price() && isset( $disco_price_cache[ $cache_key ] ) ) { return $disco_price_cache[ $cache_key ]; } $running = true; // Remove other filters that might interfere (safety for sale override). remove_filter( 'woocommerce_product_get_sale_price', '__return_false' ); remove_filter( 'woocommerce_product_get_price', '__return_false' ); $discounted_price = disco_get_discounted_price( $price, $product ); // Respect WooCommerce native sale price if it's lower if ( $product->get_type() !== 'variable' ) { $sale_price = $product->get_sale_price(); if ( $sale_price && $sale_price < $discounted_price ) { $discounted_price = $sale_price; } } $running = false; $result = round( $discounted_price, wc_get_price_decimals() ); // Cache result on safe pages if ( disco_should_cache_price() ) { $disco_price_cache[ $cache_key ] = $result; } return $result; } // Apply to simple and variation product prices (priority 999 for better compatibility) add_filter( 'woocommerce_product_get_price', 'disco_discounted_price', 999, 2 ); add_filter( 'woocommerce_product_get_sale_price', 'disco_discounted_price', 999, 2 ); add_filter( 'woocommerce_product_variation_get_price', 'disco_discounted_price', 999, 2 ); add_filter( 'woocommerce_product_variation_get_sale_price', 'disco_discounted_price', 999, 2 ); } if ( ! function_exists( 'disco_variable_product_discounted_price_html' ) ) { /** * Show variable price range with discount — includes tax if tax is enabled. * * @param string $price_html Price HTML. * @param \WC_Product $product Product Object. * @return string */ function disco_variable_product_discounted_price_html( $price_html, $product ) { if ( ! $product instanceof WC_Product_Variable ) { return $price_html; } $variation_ids = $product->get_children(); $regular_prices = array(); $discounted_prices = array(); // Use cached tax settings to avoid repeated get_option() calls $tax = Settings::get_tax_settings(); foreach ( $variation_ids as $variation_id ) { $variation = wc_get_product( $variation_id ); if ( ! $variation || ! $variation->is_purchasable() ) { continue; } if ( $tax['enabled'] && $tax['include_tax'] ) { $regular_price = wc_get_price_including_tax( $variation, [ 'price' => $variation->get_regular_price() ] ); $sale_price = wc_get_price_including_tax( $variation, [ 'price' => $variation->get_price() ] ); } else { $regular_price = (float) $variation->get_regular_price(); $sale_price = (float) $variation->get_price(); } if ( $regular_price <= 0 ) { continue; } $regular_prices[] = $regular_price; $discounted_prices[] = $sale_price; } if ( empty( $regular_prices ) || empty( $discounted_prices ) ) { return $price_html; } $regular_min = min( $regular_prices ); $regular_max = max( $regular_prices ); $discounted_min = min( $discounted_prices ); $discounted_max = max( $discounted_prices ); $is_discount_applied = ( round( $regular_min, 2 ) > round( $discounted_min, 2 ) || round( $regular_max, 2 ) > round( $discounted_max, 2 ) ); if ( ! $is_discount_applied ) { return $price_html; } /** * If min and max prices are the same, show single price. * Otherwise, show price range. * Strike-through regular price based on Disco settings. */ if ( round( $discounted_min, 2 ) === round( $discounted_max, 2 ) ) { if ( ! Disco::is_strike_through_applicable( Disco::get_page_name() ) ) { return wc_price( $discounted_min ); } return '' . wc_price( $regular_min ) . ' ' . wc_price( $discounted_min ) . ''; } $discount_range = wc_price( $discounted_min ) . ' – ' . wc_price( $discounted_max ); $regular_range = wc_price( $regular_min ) . ' – ' . wc_price( $regular_max ); if( ! Disco::is_strike_through_applicable( Disco::get_page_name() ) ) { return $discount_range; } return '' . $regular_range . '
' . $discount_range . ''; } add_filter( 'woocommerce_variable_price_html', 'disco_variable_product_discounted_price_html', 999, 2 ); } if ( ! function_exists( 'disco_discounted_price_html' ) ) { /** * Display Product Sale Price & Regular Price with or without Tax. * * @param string $price_html Product Price HTML. * @param \WC_Product $product Product Object. */ function disco_discounted_price_html( string $price_html, WC_Product $product ): string { if ( ! $product || ! is_a( $product, 'WC_Product' ) ) { return $price_html; } if( $product->get_type() === 'variable' ) { return $price_html; } // Use cached tax settings to avoid repeated get_option() calls $tax = Settings::get_tax_settings(); if ( $tax['enabled'] && $tax['include_tax'] ) { $regular_price = wc_get_price_including_tax( $product, array( 'price' => $product->get_regular_price() ) ); $sale_price = wc_get_price_including_tax( $product, array( 'price' => $product->get_price() ) ); } else { $regular_price = wc_get_price_excluding_tax( $product, array( 'price' => $product->get_regular_price() ) ); $sale_price = wc_get_price_excluding_tax( $product, array( 'price' => $product->get_price() ) ); } $page_name = Disco::get_page_name(); if ( ! Disco::is_strike_through_applicable( $page_name ) && in_array( Settings::get( 'on_sale_badge' ), [ 'show_all', 'do_not_show' ], true ) ) { return wc_price( $sale_price ); } if ( $sale_price < $regular_price ) { $price_html = '' . wc_price( $regular_price ) . ' ' . wc_price( $sale_price ) . ''; } return $price_html; } add_filter( 'woocommerce_get_price_html', 'disco_discounted_price_html', 999, 2 ); } if ( ! function_exists( 'disco_show_product_as_on_sale' ) ) { /** * Show variable product as on sale if any variation is on sale. * * @param bool $is_on_sale Whether the product is on sale. * @param \WC_Product $product Product Object. * @return bool */ function disco_show_product_as_on_sale( $is_on_sale, $product ) { if ( ! $product || ! is_a( $product, 'WC_Product' ) ) { return $is_on_sale; } $on_sale_status = Settings::get( 'on_sale_badge' ); //Show on sale badge based on WooCommerce and Disco settings. if ( 'do_not_show' === $on_sale_status ) { return false; } if( 'show_all' === $on_sale_status ) { if ( $product->is_type( 'variable' ) ) { $children = $product->get_children(); foreach ( $children as $variation_id ) { $variation = wc_get_product( $variation_id ); if ( ! $variation || ! $variation->is_purchasable() ) { continue; } $regular_price = (float) $variation->get_regular_price(); $current_price = (float) $variation->get_price(); // This includes filters (like discounts) // If the variation has a price reduction (dynamic or static) if ( $regular_price > 0 && $current_price < $regular_price ) { return true; } } } // For simple products, check if the price is discounted. $regular_price = (float) $product->get_regular_price(); $current_price = (float) $product->get_price(); // If the product has a price reduction (dynamic or static) if ( $regular_price > 0 && $current_price < $regular_price ) { return true; } } return $is_on_sale; } add_filter( 'woocommerce_product_is_on_sale', 'disco_show_product_as_on_sale', 20, 2 ); }