PluginProbe
Discount Rules for WooCommerce – Disco | Dynamic Pricing, Conditions, Bulk, Bundle, BOGO / 1.3.10
Discount Rules for WooCommerce – Disco | Dynamic Pricing, Conditions, Bulk, Bundle, BOGO v1.3.10
1.4.15 1.4.14 1.4.13 1.4.12 1.4.11 1.4.10 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.54 1.3.53 1.3.52 1.3.51 1.3.50 1.3.49 1.3.48 1.3.47 1.3.46 All 178 releases
disco / functions / product.php

product.php in Discount Rules for WooCommerce – Disco | Dynamic Pricing, Conditions, Bulk, Bundle, BOGO 1.3.10, at functions/product.php

356 lines 10.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php // phpcs:disable
2 /**
3 * Disco
4 *
5 * @package Disco
6 * @author Ohidul Islam <wahid0003@gmail.com>
7 * @link http://domain.tld
8 * @license GPL 2.0+
9 * @copyright 2022 WebAppick
10 */
11
12 // Ensure the file is not accessed directly.
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit;
15 }
16
17 use Disco\App\Disco;
18 use Disco\App\Utility\Settings;
19
20 if ( !function_exists( 'disco_get_discounted_price' ) ) {
21
22 /**
23 * Get the discounted price of a product.
24 *
25 * @param float $price Product Price.
26 * @param \WC_Product $product Product Object.
27 * @return float
28 */
29 function disco_get_discounted_price( $price, $product ) {
30 if ( is_admin() && ! defined( 'DOING_AJAX' ) ) {
31 return $price; // Return original price in admin area.
32 }
33
34 return ( new Disco )->get_product_discounted_price( $price, $product );
35 }
36
37 }
38
39 if ( ! function_exists( 'disco_init_price_cache' ) ) {
40
41 /**
42 * Initialize the global price cache.
43 *
44 * @return void
45 */
46 function disco_init_price_cache() {
47 global $disco_price_cache;
48
49 if ( ! isset( $disco_price_cache ) ) {
50 $disco_price_cache = [];
51 }
52 }
53
54 // Initialize cache on load
55 disco_init_price_cache();
56 }
57
58 if ( ! function_exists( 'disco_should_cache_price' ) ) {
59
60 /**
61 * Check if current page should use price cache.
62 * Don't cache on checkout/cart/thankyou where user limits may change.
63 *
64 * @return bool
65 */
66 function disco_should_cache_price() {
67 // Allow filter to force disable cache (useful for tests)
68 if ( apply_filters( 'disco_disable_price_cache', false ) ) {
69 return false;
70 }
71
72 // Don't cache during AJAX (cart updates, checkout, etc.)
73 if ( wp_doing_ajax() ) {
74 return false;
75 }
76
77 // Don't cache on checkout or cart pages
78 if ( function_exists( 'is_checkout' ) && is_checkout() ) {
79 return false;
80 }
81
82 if ( function_exists( 'is_cart' ) && is_cart() ) {
83 return false;
84 }
85
86 // Cache on shop, category, product pages
87 return true;
88 }
89 }
90
91 if ( ! function_exists( 'disco_clear_price_cache' ) ) {
92
93 /**
94 * Clear the discounted price cache.
95 *
96 * @return void
97 */
98 function disco_clear_price_cache() {
99 global $disco_price_cache;
100 $disco_price_cache = [];
101 }
102 }
103
104 if ( ! function_exists( 'disco_discounted_price' ) ) {
105
106 /**
107 * Applies discounted price logic to product prices (simple + variation).
108 *
109 * @param float $price Product Price.
110 * @param \WC_Product $product Product Object.
111 * @return float
112 */
113 function disco_discounted_price( $price, $product ) {
114 global $disco_price_cache;
115 static $running = false;
116
117 if ( $running || ! is_object( $product ) || ! $price ) {
118 return $price;
119 }
120
121 $product_id = $product->get_id();
122 $cache_key = $product_id . '_' . $price;
123
124 // Use cache only on safe pages (shop, category, product)
125 if ( disco_should_cache_price() && isset( $disco_price_cache[ $cache_key ] ) ) {
126 return $disco_price_cache[ $cache_key ];
127 }
128
129 $running = true;
130
131 // Remove other filters that might interfere (safety for sale override).
132 remove_filter( 'woocommerce_product_get_sale_price', '__return_false' );
133 remove_filter( 'woocommerce_product_get_price', '__return_false' );
134
135 $discounted_price = disco_get_discounted_price( $price, $product );
136
137 // Respect WooCommerce native sale price if it's lower
138 if ( $product->get_type() !== 'variable' ) {
139 $sale_price = $product->get_sale_price();
140
141 if ( $sale_price && $sale_price < $discounted_price ) {
142 $discounted_price = $sale_price;
143 }
144 }
145
146 $running = false;
147
148 $result = round( $discounted_price, wc_get_price_decimals() );
149
150 // Cache result on safe pages
151 if ( disco_should_cache_price() ) {
152 $disco_price_cache[ $cache_key ] = $result;
153 }
154
155 return $result;
156 }
157
158 // Apply to simple and variation product prices (priority 999 for better compatibility)
159 add_filter( 'woocommerce_product_get_price', 'disco_discounted_price', 999, 2 );
160 add_filter( 'woocommerce_product_get_sale_price', 'disco_discounted_price', 999, 2 );
161 add_filter( 'woocommerce_product_variation_get_price', 'disco_discounted_price', 999, 2 );
162 add_filter( 'woocommerce_product_variation_get_sale_price', 'disco_discounted_price', 999, 2 );
163 }
164
165 if ( ! function_exists( 'disco_variable_product_discounted_price_html' ) ) {
166
167 /**
168 * Show variable price range with discount — includes tax if tax is enabled.
169 *
170 * @param string $price_html Price HTML.
171 * @param \WC_Product $product Product Object.
172 * @return string
173 */
174 function disco_variable_product_discounted_price_html( $price_html, $product ) {
175 if ( ! $product instanceof WC_Product_Variable ) {
176 return $price_html;
177 }
178
179 $variation_ids = $product->get_children();
180 $regular_prices = array();
181 $discounted_prices = array();
182
183 // Use cached tax settings to avoid repeated get_option() calls
184 $tax = Settings::get_tax_settings();
185
186 foreach ( $variation_ids as $variation_id ) {
187 $variation = wc_get_product( $variation_id );
188
189 if ( ! $variation || ! $variation->is_purchasable() ) {
190 continue;
191 }
192
193 if ( $tax['enabled'] && $tax['include_tax'] ) {
194 $regular_price = wc_get_price_including_tax( $variation, [ 'price' => $variation->get_regular_price() ] );
195 $sale_price = wc_get_price_including_tax( $variation, [ 'price' => $variation->get_price() ] );
196 } else {
197 $regular_price = (float) $variation->get_regular_price();
198 $sale_price = (float) $variation->get_price();
199 }
200
201 if ( $regular_price <= 0 ) {
202 continue;
203 }
204
205 $regular_prices[] = $regular_price;
206 $discounted_prices[] = $sale_price;
207 }
208
209 if ( empty( $regular_prices ) || empty( $discounted_prices ) ) {
210 return $price_html;
211 }
212
213 $regular_min = min( $regular_prices );
214 $regular_max = max( $regular_prices );
215 $discounted_min = min( $discounted_prices );
216 $discounted_max = max( $discounted_prices );
217
218 $is_discount_applied = (
219 round( $regular_min, 2 ) > round( $discounted_min, 2 ) ||
220 round( $regular_max, 2 ) > round( $discounted_max, 2 )
221 );
222
223 if ( ! $is_discount_applied ) {
224 return $price_html;
225 }
226
227 /**
228 * If min and max prices are the same, show single price.
229 * Otherwise, show price range.
230 * Strike-through regular price based on Disco settings.
231 */
232 if ( round( $discounted_min, 2 ) === round( $discounted_max, 2 ) ) {
233 if ( ! Disco::is_strike_through_applicable( Disco::get_page_name() ) ) {
234 return wc_price( $discounted_min );
235 }
236 return '<del>' . wc_price( $regular_min ) . '</del> <ins>' . wc_price( $discounted_min ) . '</ins>';
237 }
238
239 $discount_range = wc_price( $discounted_min ) . '' . wc_price( $discounted_max );
240 $regular_range = wc_price( $regular_min ) . '' . wc_price( $regular_max );
241
242 if( ! Disco::is_strike_through_applicable( Disco::get_page_name() ) ) {
243 return $discount_range;
244 }
245
246 return '<del>' . $regular_range . '</del><br><ins>' . $discount_range . '</ins>';
247 }
248
249 add_filter( 'woocommerce_variable_price_html', 'disco_variable_product_discounted_price_html', 999, 2 );
250 }
251
252 if ( ! function_exists( 'disco_discounted_price_html' ) ) {
253
254 /**
255 * Display Product Sale Price & Regular Price with or without Tax.
256 *
257 * @param string $price_html Product Price HTML.
258 * @param \WC_Product $product Product Object.
259 */
260 function disco_discounted_price_html( string $price_html, WC_Product $product ): string {
261
262 if ( ! $product || ! is_a( $product, 'WC_Product' ) ) {
263 return $price_html;
264 }
265
266 if( $product->get_type() === 'variable' ) {
267 return $price_html;
268 }
269
270 // Use cached tax settings to avoid repeated get_option() calls
271 $tax = Settings::get_tax_settings();
272
273 if ( $tax['enabled'] && $tax['include_tax'] ) {
274 $regular_price = wc_get_price_including_tax( $product, array( 'price' => $product->get_regular_price() ) );
275 $sale_price = wc_get_price_including_tax( $product, array( 'price' => $product->get_price() ) );
276 } else {
277 $regular_price = wc_get_price_excluding_tax( $product, array( 'price' => $product->get_regular_price() ) );
278 $sale_price = wc_get_price_excluding_tax( $product, array( 'price' => $product->get_price() ) );
279 }
280
281 $page_name = Disco::get_page_name();
282
283 if (
284 ! Disco::is_strike_through_applicable( $page_name ) &&
285 in_array( Settings::get( 'on_sale_badge' ), [ 'show_all', 'do_not_show' ], true )
286 ) {
287 return wc_price( $sale_price );
288 }
289
290 if ( $sale_price < $regular_price ) {
291 $price_html = '<del>' . wc_price( $regular_price ) . '</del> <ins>' . wc_price( $sale_price ) . '</ins>';
292 }
293
294 return $price_html;
295 }
296
297 add_filter( 'woocommerce_get_price_html', 'disco_discounted_price_html', 999, 2 );
298 }
299
300 if ( ! function_exists( 'disco_show_product_as_on_sale' ) ) {
301
302 /**
303 * Show variable product as on sale if any variation is on sale.
304 *
305 * @param bool $is_on_sale Whether the product is on sale.
306 * @param \WC_Product $product Product Object.
307 * @return bool
308 */
309 function disco_show_product_as_on_sale( $is_on_sale, $product ) {
310 if ( ! $product || ! is_a( $product, 'WC_Product' ) ) {
311 return $is_on_sale;
312 }
313
314 $on_sale_status = Settings::get( 'on_sale_badge' );
315
316 //Show on sale badge based on WooCommerce and Disco settings.
317 if ( 'do_not_show' === $on_sale_status ) {
318 return false;
319 }
320
321 if( 'show_all' === $on_sale_status ) {
322 if ( $product->is_type( 'variable' ) ) {
323 $children = $product->get_children();
324
325 foreach ( $children as $variation_id ) {
326 $variation = wc_get_product( $variation_id );
327
328 if ( ! $variation || ! $variation->is_purchasable() ) {
329 continue;
330 }
331
332 $regular_price = (float) $variation->get_regular_price();
333 $current_price = (float) $variation->get_price(); // This includes filters (like discounts)
334
335 // If the variation has a price reduction (dynamic or static)
336 if ( $regular_price > 0 && $current_price < $regular_price ) {
337 return true;
338 }
339 }
340 }
341
342 // For simple products, check if the price is discounted.
343 $regular_price = (float) $product->get_regular_price();
344 $current_price = (float) $product->get_price();
345 // If the product has a price reduction (dynamic or static)
346 if ( $regular_price > 0 && $current_price < $regular_price ) {
347 return true;
348 }
349 }
350
351 return $is_on_sale;
352 }
353
354 add_filter( 'woocommerce_product_is_on_sale', 'disco_show_product_as_on_sale', 20, 2 );
355 }
356