PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 3.4.2
ShopBuilder – WooCommerce Builder For Elementor v3.4.2
3.4.2 3.4.1 3.4.0 2.0.1 2.0.2 2.0.3 2.1.0 2.1.1 2.1.10 2.1.11 2.1.12 2.1.13 2.1.14 2.1.15 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.1.7 2.1.8 2.1.9 2.2.0 2.2.1 2.2.2 All 63 releases
shopbuilder / app / Controllers / ThemesSupport / Astra / WidgetsSupport.php

WidgetsSupport.php in ShopBuilder – WooCommerce Builder For Elementor 3.4.2, at app/Controllers/ThemesSupport/Astra/WidgetsSupport.php

480 lines 15.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Main ProductDescription class.
4 *
5 * @package RadiusTheme\SB
6 */
7
8 namespace RadiusTheme\SB\Controllers\ThemesSupport\Astra;
9
10 // Do not allow directly accessing this file.
11 use Rtwpvsp\Controllers\ShopPage;
12
13 if ( ! defined( 'ABSPATH' ) ) {
14 exit( 'This script cannot be accessed directly.' );
15 }
16
17 /**
18 * Product Description class
19 */
20 class WidgetsSupport {
21
22 /**
23 * The single instance of the class.
24 *
25 * @var object
26 */
27 protected static $instance = null;
28
29 /**
30 * The single instance of the class.
31 *
32 * @var object
33 */
34 private $widgets;
35
36 /**
37 * Construct function
38 */
39 private function __construct() {
40 }
41
42 /**
43 * Get class instance.
44 *
45 * @param object $widgets Widgets reference object.
46 *
47 * @return object Instance.
48 */
49 public static function instance( $widgets ) {
50 if ( ! self::$instance ) {
51 self::$instance = new self();
52 }
53 self::$instance->widgets = $widgets;
54
55 return self::$instance;
56 }
57
58 /**
59 * Remove Astra flash sale cards buttons HTML.
60 *
61 * @param string $html Cards buttons HTML.
62 *
63 * @return string
64 */
65 public function astra_flash_sale_html_remove( $html ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
66 return '';
67 }
68
69
70 /**
71 * Astra Wrapper
72 *
73 * @return void
74 */
75 public function astra_woo_shop_thumbnail_wrap_start() {
76 echo '<div class="astra-shop-thumbnail-wrap rtsb-image-wrapper">';
77 }
78
79 /**
80 * Product Loop content Modify.
81 *
82 * @return void
83 */
84 public function astra_product_loop() {
85 $controllers = $this->widgets->get_settings_for_display();
86
87 if ( ! apply_filters( 'astra_woo_shop_product_structure_override', false ) ) {
88 // Remove some hooks.
89 remove_action( 'woocommerce_before_shop_loop_item', 'astra_woo_shop_thumbnail_wrap_start', 6 );
90 remove_action( 'woocommerce_after_shop_loop_item_title', 'woocommerce_template_loop_rating', 5 );
91 remove_action( 'woocommerce_shop_loop_item_title', 'woocommerce_template_loop_product_title', 10 );
92 remove_action( 'woocommerce_after_shop_loop_item_title', 'woocommerce_template_loop_price', 10 );
93 remove_action( 'woocommerce_after_shop_loop_item', 'woocommerce_template_loop_add_to_cart', 10 );
94
95 // Adding some hooks.
96 add_action( 'woocommerce_before_shop_loop_item', [ $this, 'astra_woo_shop_thumbnail_wrap_start' ], 6 );
97 add_action( 'woocommerce_after_shop_loop_item', 'astra_woo_shop_thumbnail_wrap_end', 8 );
98 add_action( 'woocommerce_after_shop_loop_item', 'astra_woo_woocommerce_shop_product_content' );
99 add_action( 'astra_woo_shop_before_summary_wrap', [ $this->widgets, 'product_content_wrapper' ], 6 );
100 add_action( 'astra_woo_shop_after_summary_wrap', [ $this->widgets, 'div_close' ], 6 );
101
102 if ( empty( $controllers['show_flash_sale'] ) ) {
103 if ( ! defined( 'ASTRA_EXT_VER' ) || ( defined( 'ASTRA_EXT_VER' ) && ! \Astra_Ext_Extension::is_active( 'woocommerce' ) ) ) {
104 add_filter( 'astra_addon_shop_cards_buttons_html', [ $this, 'astra_flash_sale_html_remove' ] );
105 }
106 }
107 }
108 $this->widgets->apply_hooks_set_default();
109
110 // Variation Swatch fix.
111 if ( class_exists( 'WooProductVariationSwatches' ) ) {
112 $swatches_position = rtwpvs()->get_option( 'archive_swatches_position' );
113 if ( 'before_title_and_price' == $swatches_position && class_exists( ShopPage::class ) ) {
114 remove_action(
115 'woocommerce_before_shop_loop_item_title',
116 [
117 ShopPage::class,
118 'archive_variation_swatches',
119 ],
120 35
121 );
122 add_action(
123 'astra_woo_shop_title_before',
124 [
125 ShopPage::class,
126 'archive_variation_swatches',
127 ],
128 35
129 );
130 }
131 }
132
133 // Remove Action Button.
134 add_filter( 'rtsb/module/wishlist/show_button', '__return_false' );
135 add_filter( 'rtsb/module/quick_view/show_button', '__return_false' );
136 add_filter( 'rtsb/module/compare/show_button', '__return_false' );
137
138 $this->maybe_fix_flash_sale_badge_overlap();
139 }
140
141 /**
142 * Astra-only: stop the Product Badges group badge from hiding Astra's flash-sale badge.
143 *
144 * On Astra Modern shop style the flash-sale badge ( `.ast-onsale-card` ) is anchored top-left. When the
145 * Product Badges module renders its group badge above the image at that same top-left corner, the group
146 * badge sits over the flash-sale badge and hides it. ONLY in that exact situation we shift the flash-sale
147 * badge to the opposite (top-right) corner so both stay visible. Every other case bails out, so existing
148 * behaviour is untouched.
149 *
150 * @return void
151 */
152 private function maybe_fix_flash_sale_badge_overlap() {
153 $badge_opts = \RadiusTheme\SB\Helpers\Fns::get_options( 'modules', 'product_badges' );
154
155 // Product Badges module is off — there is no group badge to overlap.
156 if ( 'on' !== ( $badge_opts['active'] ?? '' ) ) {
157 return;
158 }
159 // "Hide Theme Badges" is on — the module already removes the flash-sale badge, nothing to reposition.
160 if ( ! empty( $badge_opts['hide_woocommerce_badge'] ) ) {
161 return;
162 }
163 // Group badge is not rendered on the image, so it cannot overlap the flash-sale badge.
164 if ( 'above_image' !== ( $badge_opts['loop_group_position'] ?? '' ) ) {
165 return;
166 }
167 // Only the top-left corner clashes with Astra's (top-left) flash-sale badge.
168 if ( 'top-left' !== ( $badge_opts['group_badge_position'] ?? '' ) ) {
169 return;
170 }
171
172 add_action( 'woocommerce_before_shop_loop_item', [ $this, 'flash_sale_badge_position_style' ], 1 );
173 }
174
175 /**
176 * Print, once per request, the CSS that moves Astra's flash-sale badge to the top-right corner.
177 *
178 * The sibling selector only matches products that actually carry a group badge ( `.rtsb-badge-container` ),
179 * and `.ast-onsale-card` exists only on Astra, so the rule cannot affect other themes or non-badged products.
180 *
181 * @return void
182 */
183 public function flash_sale_badge_position_style() {
184 static $printed = false;
185 if ( $printed ) {
186 return;
187 }
188 $printed = true;
189
190 echo '<style id="rtsb-astra-flash-sale-pos">.rtsb-badge-container ~ .ast-onsale-card{left:auto !important;right:20px !important;}</style>';
191 }
192
193 /**
194 * Product Content Reset.
195 *
196 * @return void
197 */
198 public function astra_product_loop_reset_default() {
199 $controllers = $this->widgets->get_settings_for_display();
200
201 if ( ! apply_filters( 'astra_woo_shop_product_structure_override', false ) ) {
202 // Remove Product Content Wrapper.
203 remove_action( 'astra_woo_shop_before_summary_wrap', [ $this->widgets, 'product_content_wrapper' ], 6 );
204 remove_action( 'astra_woo_shop_after_summary_wrap', [ $this->widgets, 'div_close' ], 6 );
205 if ( empty( $controllers['show_flash_sale'] ) ) {
206 if ( ! defined( 'ASTRA_EXT_VER' ) || ( defined( 'ASTRA_EXT_VER' ) && ! \Astra_Ext_Extension::is_active( 'woocommerce' ) ) ) {
207 remove_filter( 'astra_addon_shop_cards_buttons_html', [ $this, 'astra_flash_sale_html_remove' ] );
208 }
209 }
210 }
211 }
212
213 /**
214 * The function name comes from the widget base name "rtsb-products-archive". This is for theme support prefix with render.
215 *
216 * @return void
217 */
218 public function render_rtsb_products_archive() {
219 $this->astra_product_loop();
220 }
221
222 /**
223 *
224 * @return void
225 */
226 public function render_reset_rtsb_products_archive() {
227 $this->astra_product_loop_reset_default();
228 }
229 /**
230 * The function name comes from the widget base name "rtsb-products-archive". This is for theme support prefix with render.
231 *
232 * @return void
233 */
234 public function render_rtsb_product_rating() {
235 remove_filter( 'woocommerce_product_get_rating_html', [ \Astra_Woocommerce::get_instance(), 'rating_markup' ], 10 );
236 }
237 /**
238 * The function name comes from the widget base name "rtsb-products-archive". This is for theme support prefix with render.
239 *
240 * @return void
241 */
242 public function render_rtsb_upsells_product() {
243 $this->astra_product_loop();
244 }
245
246 /**
247 * Reset Hooks.
248 *
249 * @return void
250 */
251 public function render_reset_rtsb_upsells_product() {
252 $this->astra_product_loop_reset_default();
253 }
254
255 /**
256 * Related Product.
257 *
258 * @return void
259 */
260 public function render_rtsb_related_product() {
261 $this->astra_product_loop();
262 }
263
264 /**
265 * Related Product.
266 *
267 * @return void
268 */
269 public function render_reset_rtsb_related_product() {
270 $this->astra_product_loop_reset_default();
271 }
272
273 /**
274 * Cross Sell Product.
275 *
276 * @return void
277 */
278 public function render_rtsb_cross_sells() {
279 $this->astra_product_loop();
280 }
281
282 /**
283 * Cross Sell Product.
284 *
285 * @return void
286 */
287 public function render_reset_rtsb_cross_sells() {
288 $this->astra_product_loop_reset_default();
289 }
290
291 /**
292 * Cross Sell Product.
293 *
294 * @return void
295 */
296 public function render_rtsb_product_onsale() {
297 add_filter( 'woocommerce_sale_flash', [ \Astra_Woocommerce::get_instance(), 'get_sale_flash_markup' ], 10, 3 );
298 }
299 /**
300 * Cross Sell Product.
301 *
302 * @return void
303 */
304 public function render_rtsb_product_stock() {
305 remove_filter( 'woocommerce_get_stock_html', 'astra_woo_product_in_stock', 10, 2 );
306 }
307
308 /**
309 * Product Images widget: make the "Show Flash Sale?" toggle authoritative on Astra.
310 *
311 * Astra registers its own `woocommerce_sale_flash` filter that rewrites and relocates the
312 * badge markup, so the widget's template gate (OFF) and its `.onsale` position/style controls
313 * (ON) are both overridden. We hook the same filter at a late priority so the toggle wins:
314 * OFF removes the badge from every source, ON restores WooCommerce's default `.onsale` markup
315 * the widget's selectors are built around.
316 *
317 * Method name derives from the widget base "rtsb-product-image" (see ElementorWidgetBase::theme_support).
318 *
319 * @return void
320 */
321 public function render_rtsb_product_image() {
322 $controllers = $this->widgets->get_settings_for_display();
323
324 if ( empty( $controllers['sale_flash_badge'] ) ) {
325 add_filter( 'woocommerce_sale_flash', '__return_empty_string', 99 );
326 } else {
327 add_filter( 'woocommerce_sale_flash', [ $this, 'default_sale_flash_markup' ], 99 );
328 }
329 }
330
331 /**
332 * Reset the Product Images sale-flash overrides after the widget renders.
333 *
334 * @return void
335 */
336 public function render_reset_rtsb_product_image() {
337 $controllers = $this->widgets->get_settings_for_display();
338
339 if ( empty( $controllers['sale_flash_badge'] ) ) {
340 remove_filter( 'woocommerce_sale_flash', '__return_empty_string', 99 );
341 } else {
342 remove_filter( 'woocommerce_sale_flash', [ $this, 'default_sale_flash_markup' ], 99 );
343 }
344 }
345
346 /**
347 * Force WooCommerce's default sale-flash markup so the Product Images widget's
348 * own `.onsale` position and style controls apply on Astra.
349 *
350 * @param string $html Existing sale-flash markup (from Astra or WooCommerce).
351 *
352 * @return string
353 */
354 public function default_sale_flash_markup( $html ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found
355 return '<span class="onsale">' . esc_html__( 'Sale!', 'shopbuilder' ) . '</span>';
356 }
357
358 /**
359 * The function name comes from the widget base name "rtsb-products-archive". This is for theme support prefix with widget_controls.
360 *
361 * @return void
362 */
363 public function widget_controls_rtsb_product_tabs() {
364 add_filter( 'rtsb/elements/elementor/widgets/controls/rtsb-product-tabs', [ $this, 'product_tabs_widget_controls_support' ] );
365 }
366
367 /**
368 * Widget Field.
369 *
370 * @param array $fields Widget fields.
371 *
372 * @return array
373 */
374 public function product_tabs_widget_controls_support( $fields ) {
375 $fields['nav_active_border_color']['selectors'] = array_merge(
376 $fields['nav_active_border_color']['selectors'],
377 [
378 '{{WRAPPER}} .woocommerce-tabs ul.tabs li.active:before' => 'background: {{VALUE}}',
379 ]
380 );
381 $fields['nav_active_hover_border_color']['selectors'] = array_merge(
382 $fields['nav_active_hover_border_color']['selectors'],
383 [
384 '{{WRAPPER}} .woocommerce-tabs ul.tabs li.active:hover:before' => 'background: {{VALUE}}',
385 ]
386 );
387
388 return $fields;
389 }
390
391 /**
392 * The function name comes from the widget base name "rtsb-products-archive". This is for theme support prefix with "widget_controls".
393 *
394 * @return void
395 */
396 public function widget_controls_rtsb_products_archive() {
397 add_filter( 'rtsb/elements/elementor/widgets/controls/rtsb-products-archive', [ $this, 'product_loop_widget_controls_support' ], 11 );
398 }
399
400 /**
401 * Widget Field.
402 *
403 * @param array $fields Widget fields.
404 *
405 * @return array
406 */
407 public function product_loop_widget_controls_support( $fields ) {
408 if ( $this->widgets->has_pagination ) {
409 $fields['prev_icon']['default'] = [
410 'value' => 'fas fa-long-arrow-alt-left',
411 'library' => 'fa-solid',
412 ];
413 $fields['next_icon']['default'] = [
414 'value' => 'fas fa-long-arrow-alt-right',
415 'library' => 'fa-solid',
416 ];
417 }
418 $astra_onsale_card = '{{WRAPPER}} .products .product .ast-onsale-card';
419 if ( ! empty( $fields['flash_sale_typography']['selector'] ) ) {
420 $fields['flash_sale_typography']['selector'] = $fields['flash_sale_typography']['selector'] . ',' . $astra_onsale_card;
421 }
422 if ( ! empty( $fields['product_flash_sale_color']['selectors'] ) ) {
423 $fields['product_flash_sale_color']['selectors'][ $astra_onsale_card ] = 'color: {{VALUE}};';
424 }
425 if ( ! empty( $fields['flash_sale_bg_color']['selectors'] ) ) {
426 $fields['flash_sale_bg_color']['selectors'][ $astra_onsale_card ] = 'background-color: {{VALUE}};';
427 }
428 if ( ! empty( $fields['flash_sale_badge_width']['selectors'] ) ) {
429 $fields['flash_sale_badge_width']['selectors'][ $astra_onsale_card ] = 'width: {{SIZE}}{{UNIT}}; text-align: center;';
430 }
431 if ( ! empty( $fields['flash_sale_badge_height']['selectors'] ) ) {
432 $fields['flash_sale_badge_height']['selectors'][ $astra_onsale_card ] = 'height: {{SIZE}}{{UNIT}};';
433 }
434 if ( ! empty( $fields['flash_sale_badge_border_radius']['selectors'] ) ) {
435 $fields['flash_sale_badge_border_radius']['selectors'][ $astra_onsale_card ] = 'border-radius: {{SIZE}}{{UNIT}};';
436 }
437 return $fields;
438 }
439
440 /**
441 * The function name comes from the widget base name "rtsb-products-archive". This is for theme support prefix with widget_controls.
442 *
443 * @return void
444 */
445 public function widget_controls_rtsb_related_product() {
446 add_filter( 'rtsb/elements/elementor/widgets/controls/rtsb-related-product', [ $this, 'widget_controls_flash_sale' ] );
447 }
448
449 /**
450 * @return void
451 */
452 public function widget_controls_rtsb_upsells_product() {
453 add_filter( 'rtsb/elements/elementor/widgets/controls/rtsb-upsells-product', [ $this, 'widget_controls_flash_sale' ] );
454 }
455 /**
456 * @return void
457 */
458 public function widget_controls_rtsb_cross_sells() {
459 add_filter( 'rtsb/elements/elementor/widgets/controls/rtsb-cross-sells', [ $this, 'widget_controls_flash_sale' ] );
460 }
461 /**
462 * Widget Field.
463 *
464 * @param array $fields Widget fields.
465 *
466 * @return array
467 */
468 public function widget_controls_flash_sale( $fields ) {
469 $selector = '{{WRAPPER}} .products .product .ast-onsale-card';
470 $fields['flash_sale_typography']['selector'] = $selector;
471 $fields['product_flash_sale_color']['selectors'][ $selector ] = 'color: {{VALUE}};';
472 $fields['flash_sale_bg_color']['selectors'][ $selector ] = 'background-color: {{VALUE}};';
473 $fields['flash_sale_badge_width']['selectors'][ $selector ] = 'width: {{SIZE}}{{UNIT}};display:flex; justify-content: center;';
474 $fields['flash_sale_badge_height']['selectors'][ $selector ] = 'height: {{SIZE}}{{UNIT}};align-items:center;';
475 $fields['flash_sale_badge_border_radius']['selectors'][ $selector ] = 'border-radius: {{SIZE}}{{UNIT}};';
476
477 return $fields;
478 }
479 }
480