PluginProbe
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant / 1.11.2
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant v1.11.2
2.3.2 2.3.1 2.3.0 2.2.8 2.2.7 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.11.0 1.11.1 1.11.2 1.6 1.7 1.8 1.8.1 1.8.2 1.8.3 1.9.0 1.9.1 1.9.10 1.9.11 All 60 releases
merchant / inc / modules / quick-view / class-quick-view.php

class-quick-view.php in Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant 1.11.2, at inc/modules/quick-view/class-quick-view.php

934 lines 31.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Quick View.
5 *
6 * @package Merchant
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit; // Exit if accessed directly
11 }
12
13 /**
14 * Quick View Class.
15 *
16 */
17 class Merchant_Quick_View extends Merchant_Add_Module {
18
19 /**
20 * Module ID.
21 *
22 */
23 const MODULE_ID = 'quick-view';
24
25 /**
26 * Is module preview.
27 *
28 */
29 public static $is_module_preview = false;
30
31 /**
32 * Whether the module has a shortcode or not.
33 *
34 * @var bool
35 */
36 public $has_shortcode = true;
37
38 private static $instance = null;
39
40 /**
41 * Constructor.
42 *
43 */
44 public function __construct() {
45
46 // Module id.
47 $this->module_id = self::MODULE_ID;
48
49 // WooCommerce only.
50 $this->wc_only = true;
51
52 // Parent construct.
53 parent::__construct();
54
55 // Module section.
56 $this->module_section = 'convert-more';
57
58 // Module default settings.
59 $this->module_default_settings = array(
60 'button_type' => 'text',
61 'button_text' => __( 'Quick View', 'merchant' ),
62 'button_icon' => 'eye',
63 'button_position' => 'overlay',
64 'button-position-top' => 50,
65 'button-position-left' => 50,
66 'mobile_position' => false,
67 'button-position-top-mobile' => 50,
68 'button-position-left-mobile' => 50,
69 'zoom_effect' => 1,
70 'show_quantity' => 1,
71 'place_product_description' => 'top',
72 'description_style' => 'short',
73 'place_product_image' => 'thumbs-at-left',
74 'show_buy_now_button' => false,
75 'show_suggested_products' => true,
76 'suggested_products_module' => 'bulk_discounts',
77 'suggested_products_placement' => 'after_add_to_cart',
78 );
79
80 // Mount preview url.
81 $preview_url = site_url( '/' );
82
83 if ( function_exists( 'wc_get_page_id' ) ) {
84 $preview_url = get_permalink( wc_get_page_id( 'shop' ) );
85 }
86
87 // Module data.
88 $this->module_data = Merchant_Admin_Modules::$modules_data[ self::MODULE_ID ];
89 $this->module_data[ 'preview_url' ] = $preview_url;
90
91 // Module options path.
92 $this->module_options_path = MERCHANT_DIR . 'inc/modules/' . self::MODULE_ID . '/admin/options.php';
93
94 // Is module preview page.
95 if ( is_admin() && parent::is_module_settings_page() ) {
96 self::$is_module_preview = true;
97
98 // Enqueue admin styles.
99 add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_css' ) );
100
101 // Admin preview box.
102 add_filter( 'merchant_module_preview', array( $this, 'render_admin_preview' ), 10, 2 );
103
104 // Custom CSS.
105 // The custom CSS should be added here as well due to ensure preview box works properly.
106 add_filter( 'merchant_custom_css', array( $this, 'admin_custom_css' ) );
107
108 }
109
110 if ( Merchant_Modules::is_module_active( self::MODULE_ID ) && is_admin() ) {
111 // Init translations.
112 $this->init_translations();
113 }
114
115 if ( ! Merchant_Modules::is_module_active( self::MODULE_ID ) ) {
116 return;
117 }
118
119 // Return early if it's on admin but not in the respective module settings page.
120 if ( is_admin() && ! wp_doing_ajax() && ! parent::is_module_settings_page() ) {
121 return;
122 }
123
124 // Enqueue styles.
125 add_action( 'merchant_enqueue_before_main_css_js', array( $this, 'enqueue_css' ) );
126
127 // Enqueue scripts.
128 add_action( 'merchant_enqueue_after_main_css_js', array( $this, 'enqueue_scripts' ) );
129
130 // Localize script.
131 add_filter( 'merchant_localize_script', array( $this, 'localize_script' ) );
132
133 // Handle Botiga theme scripts for compatibility.
134 if ( defined( 'BOTIGA_PRO_URI' ) && defined( 'BOTIGA_PRO_VERSION' ) ) {
135 add_action( 'wp_enqueue_scripts', array( $this, 'modal_compatibility_with_botiga_theme' ) );
136 }
137
138 // Button Position.
139 if ( ! $this->is_shortcode_enabled() ) {
140 $button_position = Merchant_Admin_Options::get( self::MODULE_ID, 'button_position', 'overlay' );
141
142 if ( 'before' === $button_position ) {
143 add_action( 'woocommerce_after_shop_loop_item', array( $this, 'quick_view_button' ), 5 );
144 } elseif ( 'after' === $button_position ) {
145 add_action( 'woocommerce_after_shop_loop_item', array( $this, 'quick_view_button' ), 15 );
146 } elseif ( 'overlay' === $button_position ) {
147 if ( merchant_is_kadence_active() ) {
148 add_action( 'woocommerce_before_shop_loop_item_title', array( $this, 'quick_view_button' ), 35 );
149 //add_filter( 'kadence_archive_content_wrap_start', array( $this, 'add_quick_view_button' ) );
150 } elseif ( merchant_is_blocksy_active() ) {
151 add_action( 'blocksy:woocommerce:product-card:thumbnail:end', array( $this, 'quick_view_button' ) );
152 } elseif ( merchant_is_botiga_active() ) {
153 add_action( 'woocommerce_before_shop_loop_item_title', array( $this, 'quick_view_button' ) );
154 } elseif ( merchant_is_oceanwp_active() ) {
155 add_action( 'ocean_after_archive_product_image', array( $this, 'quick_view_button' ) );
156 } elseif ( merchant_is_flatsome_active() ) {
157 add_action( 'flatsome_woocommerce_shop_loop_images', array( $this, 'quick_view_button' ) );
158 } elseif ( merchant_is_storefront_active() ) {
159 remove_action( 'woocommerce_before_shop_loop_item_title', 'woocommerce_template_loop_product_thumbnail', 10 );
160 add_action( 'woocommerce_before_shop_loop_item_title', function () {
161 echo '<div class="merchant-storefront-thumbnail-wrapper">';
162 woocommerce_template_loop_product_thumbnail();
163 $this->quick_view_button();
164 echo '</div>';
165 } );
166 } elseif ( merchant_is_astra_active() ) {
167 add_action( 'woocommerce_after_shop_loop_item', array( $this, 'quick_view_button' ), 7 );
168 } else {
169 add_action( 'woocommerce_after_shop_loop_item', array( $this, 'quick_view_button' ) );
170 }
171 }
172 }
173
174 // Inject quick view modal output on footer.
175 add_action( 'wp_footer', array( $this, 'modal_output' ) );
176
177 // Show Suggested Module
178 $suggested_placement = Merchant_Admin_Options::get( self::MODULE_ID, 'suggested_products_placement', 'after_add_to_cart' );
179 add_action( 'merchant_quick_view_' . $suggested_placement, array( $this, 'render_suggested_module_content' ), 10, 2 );
180
181 // Show Buy Now Module
182 add_action( 'woocommerce_after_add_to_cart_button', array( $this, 'render_buy_now_button' ) );
183
184 // Custom CSS.
185 add_filter( 'merchant_custom_css', array( $this, 'frontend_custom_css' ) );
186
187 // Modal content ajax callback.
188 add_action( 'wp_ajax_merchant_quick_view_content', array( $this, 'modal_content_ajax_callback' ) );
189 add_action( 'wp_ajax_nopriv_merchant_quick_view_content', array( $this, 'modal_content_ajax_callback' ) );
190 }
191
192 /**
193 * Singleton
194 *
195 * @return self|null
196 */
197 public static function get_instance() {
198 if ( self::$instance === null ) {
199 self::$instance = new self();
200 }
201
202 return self::$instance;
203 }
204
205 /**
206 * Init translations.
207 *
208 * @return void
209 */
210 public function init_translations() {
211 $settings = $this->get_module_settings();
212 if ( ! empty( $settings['button_text'] ) ) {
213 Merchant_Translator::register_string( $settings['button_text'], esc_html__( 'Quick view button text', 'merchant' ) );
214 }
215 }
216
217 /**
218 * Print shortcode content.
219 *
220 * @return string
221 */
222 public function shortcode_handler() {
223 // Check if module is active.
224 if ( ! Merchant_Modules::is_module_active( $this->module_id ) ) {
225 return '';
226 }
227
228 // Check if shortcode is enabled.
229 if ( ! $this->is_shortcode_enabled() ) {
230 return '';
231 }
232
233 global $product;
234
235 $product_id = is_object( $product ) ? $product->get_id() : get_the_ID();
236
237 ob_start();
238 $this->quick_view_button( 'shortcode' );
239 $shortcode_content = ob_get_clean();
240
241 /**
242 * Filter the shortcode html content.
243 *
244 * @param string $shortcode_content shortcode html content
245 * @param string $module_id module id
246 * @param int $post_id product id
247 *
248 * @since 1.8
249 */
250 return apply_filters( 'merchant_module_shortcode_content_html', $shortcode_content, $this->module_id, $product_id );
251 }
252
253 /**
254 * Concatenate the quick view button with the content start wrap.
255 *
256 * @return string
257 */
258 public function add_quick_view_button() {
259 return $this->quick_view_button() . '<div class="product-details content-bg entry-content-wrap">';
260 }
261
262 /**
263 * Admin enqueue CSS.
264 *
265 * @return void
266 */
267 public function admin_enqueue_css() {
268 $page = ( ! empty( $_GET['page'] ) ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
269 $module = ( ! empty( $_GET['module'] ) ) ? sanitize_text_field( wp_unslash( $_GET['module'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
270
271 if ( 'merchant' === $page && self::MODULE_ID === $module ) {
272 wp_enqueue_style( 'merchant-' . self::MODULE_ID, MERCHANT_URI . 'assets/css/modules/' . self::MODULE_ID . '/quick-view.min.css', array(), MERCHANT_VERSION );
273 wp_enqueue_style( 'merchant-admin-' . self::MODULE_ID, MERCHANT_URI . 'assets/css/modules/' . self::MODULE_ID . '/admin/preview.min.css', array(), MERCHANT_VERSION );
274 }
275 }
276
277 /**
278 * Enqueue CSS.
279 *
280 * @return void
281 */
282 public function enqueue_css() {
283
284 // Specific module styles.
285 wp_enqueue_style( 'merchant-' . self::MODULE_ID, MERCHANT_URI . 'assets/css/modules/' . self::MODULE_ID . '/quick-view.min.css', array(), MERCHANT_VERSION );
286 }
287
288 /**
289 * Enqueue scripts.
290 *
291 * @return void
292 */
293 public function enqueue_scripts() {
294 wp_enqueue_script( 'zoom' );
295 wp_enqueue_script( 'flexslider' );
296 wp_enqueue_script( 'wc-single-product' );
297 wp_enqueue_script( 'wc-add-to-cart-variation' );
298
299 // Register and enqueue the main module script.
300 wp_enqueue_script( 'merchant-' . self::MODULE_ID, MERCHANT_URI . 'assets/js/modules/' . self::MODULE_ID . '/quick-view.min.js', array(), MERCHANT_VERSION, true );
301 }
302
303 /**
304 * Localize script with module settings.
305 *
306 * @param array $setting The merchant global object setting parameter.
307 * @return array $setting The merchant global object setting parameter.
308 */
309 public function localize_script( $setting ) {
310 $module_settings = $this->get_module_settings();
311
312 $setting[ 'quick_view' ] = true;
313 $setting[ 'quick_view_zoom' ] = $module_settings[ 'zoom_effect' ];
314
315 return $setting;
316 }
317
318 /**
319 * Enqueue botiga theme scripts.
320 *
321 * @return void
322 */
323 public function modal_compatibility_with_botiga_theme() {
324 if ( ! wp_script_is( 'botiga-product-swatch' ) ) {
325 wp_enqueue_script( 'botiga-product-swatch', BOTIGA_PRO_URI . 'assets/js/botiga-product-swatch.min.js', array(), BOTIGA_PRO_VERSION, true );
326 }
327
328 if ( ! wp_script_is( 'botiga-checkout-quantity-input' ) ) {
329 wp_enqueue_script( 'botiga-checkout-quantity-input', BOTIGA_PRO_URI . 'assets/js/botiga-checkout-quantity-input.min.js', array( 'jquery' ), BOTIGA_PRO_VERSION, true );
330 }
331 }
332
333 /**
334 * Render admin preview
335 *
336 * @param Merchant_Admin_Preview $preview
337 * @param string $module
338 *
339 * @return Merchant_Admin_Preview
340 */
341 public function render_admin_preview( $preview, $module ) {
342 if ( self::MODULE_ID === $module ) {
343 ob_start();
344 self::admin_preview_content();
345 $content = ob_get_clean();
346
347 // HTML.
348 $preview->set_html( $content );
349
350 // Button Type.
351 $preview->set_class( 'button_type', '.merchant-quick-view-button', array( 'icon', 'icon-text', 'text' ) );
352
353 // Button Text.
354 $preview->set_text( 'button_text', '.button-text' );
355
356 // Button Icon.
357 $preview->set_svg_icon( 'button_icon', '.quick-view-icon' );
358
359 // Button Position.
360 $preview->set_class( 'button_position', '.merchant-quick-view-preview', array( 'before', 'after', 'overlay' ) );
361
362 }
363
364 return $preview;
365 }
366
367 /**
368 * Admin preview content.
369 *
370 * @return void
371 */
372 public function admin_preview_content() {
373 $settings = $this->get_module_settings();
374
375 ?>
376
377 <div class="merchant-quick-view-preview <?php echo esc_attr( $settings[ 'button_position' ] ); ?>">
378 <div class="image-wrapper">
379 <div class="button-position button-position-overlay">
380 <?php $this->admin_preview_quick_view_button(); ?>
381 </div>
382 </div>
383 <h3><?php echo esc_html__( 'Product Title', 'merchant' ); ?></h3>
384 <p><?php echo esc_html__( 'The product description normally is displayed here.', 'merchant' ); ?></p>
385 <div class="button-position button-position-before">
386 <?php $this->admin_preview_quick_view_button(); ?>
387 </div>
388 <div>
389 <a href="#" class="add_to_cart_button"><?php echo esc_html__( 'Add To Cart', 'merchant' ); ?></a>
390 </div>
391 <div class="button-position button-position-after">
392 <?php $this->admin_preview_quick_view_button(); ?>
393 </div>
394
395 </div>
396
397 <?php
398 }
399
400 /**
401 * Admin preview quick view button.
402 *
403 * @return void
404 */
405 public function admin_preview_quick_view_button() {
406 $settings = $this->get_module_settings();
407
408 ?>
409
410 <a href="#" class="merchant-quick-view-button <?php echo esc_attr( $settings[ 'button_type' ] ); ?>">
411 <span class="button-type button-type-icon">
412 <span class="quick-view-icon">
413 <?php echo wp_kses( Merchant_SVG_Icons::get_svg_icon( $settings[ 'button_icon' ] ), merchant_kses_allowed_tags( array(), false ) ); ?>
414 </span>
415 </span>
416 <span class="button-type button-type-icon-text">
417 <span class="quick-view-icon">
418 <?php echo wp_kses( Merchant_SVG_Icons::get_svg_icon( $settings[ 'button_icon' ] ), merchant_kses_allowed_tags( array(), false ) ); ?>
419 </span>
420 <span class="button-text"><?php echo esc_html( $settings[ 'button_text' ] ); ?></span>
421 </span>
422 <span class="button-type button-type-text">
423 <span class="button-text"><?php echo esc_html( $settings[ 'button_text' ] ); ?></span>
424 </span>
425 </a>
426
427 <?php
428 }
429
430 /**
431 * Modal content ajax callback.
432 * TODO: Render the output through templates files.
433 *
434 * @return void
435 */
436 public function modal_content_ajax_callback() {
437 check_ajax_referer( 'merchant-nonce', 'nonce' );
438
439 if ( ! isset( $_POST['product_id'] ) || ! function_exists( 'wc_get_product' ) ) {
440 wp_send_json_error();
441 }
442
443 $args = array(
444 'product_id' => absint( $_POST['product_id'] ),
445 );
446
447 global $product;
448
449 $settings = $this->get_module_settings();
450 $product = wc_get_product( $args['product_id'] );
451
452 if ( is_wp_error( $product ) || empty( $product ) ) {
453 wp_send_json_error();
454 }
455
456 $product_id = $product->get_id();
457 $hide_quantity = ( empty( $settings[ 'show_quantity' ] ) ) ? 'merchant-hide-quantity' : '';
458
459 ob_start();
460 ?>
461 <div id="product-<?php echo absint( $product_id ); ?>" <?php wc_product_class( '', $product ); ?>>
462 <div class="merchant-quick-view-row">
463 <div class="merchant-quick-view-column">
464 <div class="merchant-quick-view-product-gallery">
465 <?php woocommerce_show_product_images(); ?>
466 </div>
467 </div>
468
469 <div class="merchant-quick-view-column">
470 <div class="merchant-quick-view-summary product-gallery-summary">
471 <div class="merchant-quick-view-product-title">
472 <h2 class="product_title entry-title"><?php echo esc_html( $product->get_title() ); ?></h2>
473 </div>
474
475 <?php if ( 0 !== $product->get_average_rating() ) : ?>
476 <div class="merchant-quick-view-product-rating">
477 <div class="woocommerce-product-rating">
478 <?php echo wp_kses( wc_get_rating_html( $product->get_average_rating() ), merchant_kses_allowed_tags() ); ?>
479 </div>
480 </div>
481 <?php endif; ?>
482
483 <div class="merchant-quick-view-product-price">
484 <div class="price"><?php echo wp_kses( $product->get_price_html(), merchant_kses_allowed_tags() ); ?></div>
485 </div>
486
487 <?php if ( 'top' === $settings[ 'place_product_description' ] ) : ?>
488 <?php
489 /**
490 * Hook 'merchant_quick_view_before_product_description'
491 *
492 * @since 1.9.14
493 */
494 do_action( 'merchant_quick_view_before_product_description' );
495
496 $description = $settings[ 'description_style' ] === 'full' ? $product->get_description() : $product->get_short_description();
497
498 /**
499 * `merchant_quick_view_description`
500 *
501 * @since 1.9.16
502 */
503 $description = apply_filters( 'merchant_quick_view_description', $description );
504 ?>
505 <div class="merchant-quick-view-product-excerpt">
506 <?php echo wp_kses_post( $description ); ?>
507 </div>
508
509 <?php
510 /**
511 * Hook 'merchant_quick_view_before_product_description'
512 *
513 * @since 1.9.14
514 */
515 do_action( 'merchant_quick_view_after_product_description' );
516 ?>
517 <?php endif; ?>
518
519 <?php
520 /**
521 * Hook 'merchant_quick_view_before_add_to_cart'
522 *
523 * @since 1.9.14
524 */
525 do_action( 'merchant_quick_view_before_add_to_cart', $product, $settings );
526 ?>
527 <div class="merchant-quick-view-product-add-to-cart <?php echo esc_attr( $hide_quantity ); ?>">
528 <?php woocommerce_template_single_add_to_cart(); ?>
529 </div>
530
531 <?php
532 /**
533 * Hook 'merchant_quick_view_after_add_to_cart'
534 *
535 * @since 1.9.14
536 */
537 do_action( 'merchant_quick_view_after_add_to_cart', $product, $settings );
538 ?>
539
540 <?php if ( 'bottom' === $settings[ 'place_product_description' ] ) : ?>
541 <?php
542 /**
543 * Hook 'merchant_quick_view_before_product_description'
544 *
545 * @since 1.9.14
546 */
547 do_action( 'merchant_quick_view_before_product_description' );
548
549 $description = $settings[ 'description_style' ] === 'full' ? $product->get_description() : $product->get_short_description();
550
551 /**
552 * `merchant_quick_view_description`
553 *
554 * @since 1.9.16
555 */
556 $description = apply_filters( 'merchant_quick_view_description', $description );
557 ?>
558 <div class="merchant-quick-view-product-excerpt">
559 <?php echo wp_kses_post( $description ); ?>
560 </div>
561
562 <?php
563 /**
564 * Hook 'merchant_quick_view_after_product_description'
565 *
566 * @since 1.9.14
567 */
568 do_action( 'merchant_quick_view_after_product_description' );
569 ?>
570 <?php endif; ?>
571 <div class="merchant-quick-view-product-meta">
572 <?php woocommerce_template_single_meta(); ?>
573 </div>
574
575 <?php
576 /**
577 * Hook 'merchant_quick_view_after_product_excerpt'
578 *
579 * @since 1.0.0
580 */
581 do_action( 'merchant_quick_view_after_product_meta' );
582 ?>
583 </div>
584 </div>
585 </div>
586 </div>
587 <?php
588 $content = ob_get_contents();
589
590 ob_get_clean();
591
592 wp_send_json_success( $content );
593 }
594
595 /**
596 * Modal output.
597 * TODO: Render the output through templates files.
598 *
599 * @return void
600 */
601 public function modal_output() {
602 $settings = $this->get_module_settings();
603 ?>
604 <div class="single-product merchant-quick-view-modal merchant-quick-view-<?php echo esc_attr( $settings[ 'place_product_image' ] ); ?>">
605 <div class="merchant-quick-view-overlay"></div>
606 <div class="merchant-quick-view-loader">
607 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
608 <path opacity="0.4" d="M478.71 364.58zm-22 6.11l-27.83-15.9a15.92 15.92 0 0 1-6.94-19.2A184 184 0 1 1 256 72c5.89 0 11.71.29 17.46.83-.74-.07-1.48-.15-2.23-.21-8.49-.69-15.23-7.31-15.23-15.83v-32a16 16 0 0 1 15.34-16C266.24 8.46 261.18 8 256 8 119 8 8 119 8 256s111 248 248 248c98 0 182.42-56.95 222.71-139.42-4.13 7.86-14.23 10.55-22 6.11z" />
609 <path d="M271.23 72.62c-8.49-.69-15.23-7.31-15.23-15.83V24.73c0-9.11 7.67-16.78 16.77-16.17C401.92 17.18 504 124.67 504 256a246 246 0 0 1-25 108.24c-4 8.17-14.37 11-22.26 6.45l-27.84-15.9c-7.41-4.23-9.83-13.35-6.2-21.07A182.53 182.53 0 0 0 440 256c0-96.49-74.27-175.63-168.77-183.38z" />
610 </svg>
611 </div>
612 <div class="merchant-quick-view-inner">
613 <a href="#" class="merchant-quick-view-close-button" title="<?php echo esc_attr__( 'Close quick view modal', 'merchant' ); ?>">
614 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
615 <path d="M193.94 256L296.5 153.44l21.15-21.15c3.12-3.12 3.12-8.19 0-11.31l-22.63-22.63c-3.12-3.12-8.19-3.12-11.31 0L160 222.06 36.29 98.34c-3.12-3.12-8.19-3.12-11.31 0L2.34 120.97c-3.12 3.12-3.12 8.19 0 11.31L126.06 256 2.34 379.71c-3.12 3.12-3.12 8.19 0 11.31l22.63 22.63c3.12 3.12 8.19 3.12 11.31 0L160 289.94 262.56 392.5l21.15 21.15c3.12 3.12 8.19 3.12 11.31 0l22.63-22.63c3.12-3.12 3.12-8.19 0-11.31L193.94 256z"/>
616 </svg>
617 </a>
618 <div class="merchant-quick-view-content"></div>
619 </div>
620 </div>
621 <?php
622 }
623
624 /**
625 * Quick view button.
626 *
627 * @return void
628 */
629 public function quick_view_button( $context = '' ) {
630 global $product;
631
632 if ( ! is_object( $product ) ) {
633 return;
634 }
635
636 $settings = $this->get_module_settings();
637 $product_id = $product->get_id();
638
639 $button_text_html = '';
640 $button_icon_html = '';
641
642 if ( 'icon' === $settings[ 'button_type' ] || 'icon-text' === $settings[ 'button_type' ] ) {
643 $button_icon_html = Merchant_SVG_Icons::get_svg_icon( $settings[ 'button_icon' ] );
644 }
645
646 if ( 'text' === $settings[ 'button_type' ] || 'icon-text' === $settings[ 'button_type' ] ) {
647 $button_text_html = '<span>' . Merchant_Translator::translate( $settings[ 'button_text' ] ) . '</span>';
648 }
649
650 $classes = 'button wp-element-button merchant-quick-view-button';
651 $classes .= $context !== 'shortcode' ? ' merchant-quick-view-position-' . ( $settings[ 'button_position' ] ?? '' ) : '';
652 $classes .= ( $context !== 'shortcode' && ! empty( $settings['mobile_position'] ) ) ? ' merchant-quick-view-position-has-mobile-position' : '';
653 ?>
654 <button class="<?php echo esc_attr( $classes ); ?>" data-product-id="<?php echo absint( $product_id ); ?>" type="button">
655 <?php echo wp_kses( $button_icon_html, merchant_kses_allowed_tags( array(), false ) ) . wp_kses_post( $button_text_html ); ?>
656 </button>
657 <?php
658 }
659
660 /**
661 * Renders the Buy Now button.
662 *
663 * @return void
664 */
665 public function render_buy_now_button() {
666 if ( ! Merchant_Modules::is_module_active( Merchant_Buy_Now::MODULE_ID ) ) {
667 return;
668 }
669
670 // Don't include on Single Product
671 if ( ! did_action( 'merchant_quick_view_before_add_to_cart' ) ) {
672 return;
673 }
674
675 $show_buy_now = (bool) Merchant_Admin_Options::get( $this->module_id, 'show_buy_now_button', false );
676 if ( ! $show_buy_now ) {
677 return;
678 }
679
680 global $product;
681
682 $text = Merchant_Admin_Options::get( Merchant_Buy_Now::MODULE_ID, 'button-text', esc_html__( 'Buy Now', 'merchant' ) );
683
684 $_wrapper_classes = array();
685 $_wrapper_classes[] = $product->get_type() === 'variable' ? 'disabled' : '';
686
687 /**
688 * Hook 'merchant_module_buy_now_wrapper_class'
689 *
690 * @since 1.8
691 */
692 $wrapper_classes = apply_filters( 'merchant_module_buy_now_wrapper_class', $_wrapper_classes );
693 ?>
694 <!-- Don't define type="submit" because it creates issue with block themes. The button is inside the form, so by default the type is already "submit". -->
695 <button name="merchant-buy-now" value="<?php echo absint( $product->get_ID() ); ?>" class="button alt wp-element-button merchant-buy-now-button <?php echo esc_attr( implode( ' ', $wrapper_classes ) ); ?>"><?php echo esc_html( Merchant_Translator::translate( $text ) ); ?></button>
696 <?php
697 }
698
699 /**
700 * Renders the suggested module content based on the provided settings.
701 *
702 * @param $product
703 * @param $settings
704 *
705 * @return void
706 */
707 public function render_suggested_module_content( $product, $settings ) {
708 $show_suggested = (bool) Merchant_Admin_Options::get( $this->module_id, 'show_suggested_products', true );
709
710 if ( ! $show_suggested || empty( $product ) ) {
711 return;
712 }
713
714 $suggested_module = $settings['suggested_products_module'] ?? 'bulk_discounts';
715
716 switch ( $suggested_module ) {
717 case 'bulk_discounts':
718 $this->print_bulk_discounts( $product );
719 break;
720
721 case 'buy_x_get_y':
722 $this->print_buy_x_get_y( $product );
723 break;
724
725 case 'frequently_bought_together':
726 $this->print_frequently_bought_together( $product );
727 break;
728 }
729 }
730
731 /**
732 * Prints the bulk discounts for the specified product.
733 *
734 * @param $product
735 *
736 * @return void
737 */
738 public function print_bulk_discounts( $product ) {
739 if ( ! merchant_is_pro_active() || ! Merchant_Modules::is_module_active( Merchant_Volume_Discounts::MODULE_ID ) ) {
740 return;
741 }
742
743 $product_id = $product->get_id();
744 $discount_tiers = Merchant_Pro_Volume_Discounts::availabe_offers( $product_id );
745
746 if ( ! empty( $discount_tiers ) ) {
747 merchant_get_template_part(
748 Merchant_Volume_Discounts::MODULE_TEMPLATES_PATH,
749 'single-product',
750 array(
751 'settings' => Merchant_Admin_Options::get_all( Merchant_Volume_Discounts::MODULE_ID ),
752 'product' => $product,
753 'discount_tiers' => $discount_tiers,
754 'product_price' => $product->get_price(),
755 'in_cart' => Merchant_Pro_Volume_Discounts::is_in_cart( $product_id ),
756 'product_cart_quantity' => Merchant_Pro_Volume_Discounts::get_product_cart_quantity( $product_id ),
757 'product_id' => $product_id,
758 )
759 );
760 }
761 }
762
763 /**
764 * Prints the Buy X Get Y offers for the specified product.
765 *
766 * @param $product
767 *
768 * @return void
769 */
770 public function print_buy_x_get_y( $product ) {
771 if ( ! merchant_is_pro_active() || ! Merchant_Modules::is_module_active( Merchant_Buy_X_Get_Y::MODULE_ID ) ) {
772 return;
773 }
774
775 $product_id = $product->get_id();
776 $offers = Merchant_Pro_Buy_X_Get_Y::availabe_offers( $product_id );
777
778 if ( ! empty( $offers ) ) {
779 merchant_get_template_part(
780 Merchant_Buy_X_Get_Y::MODULE_TEMPLATES,
781 'single-product',
782 array(
783 'offers' => $offers,
784 'nonce' => wp_create_nonce( 'merchant_bogo_add_to_cart' ),
785 'settings' => Merchant_Admin_Options::get_all( Merchant_Buy_X_Get_Y::MODULE_ID ),
786 'product' => $product_id,
787 )
788 );
789 }
790 }
791
792 /**
793 * Prints the frequently bought together bundles for the specified product.
794 *
795 * @param $product
796 *
797 * @return void
798 */
799 public function print_frequently_bought_together( $product ) {
800 if ( ! merchant_is_pro_active() || ! Merchant_Modules::is_module_active( Merchant_Frequently_Bought_Together::MODULE_ID ) ) {
801 return;
802 }
803
804 $post_id = $product->get_id();
805 $bundle_data = Merchant_Pro_Frequently_Bought_Together::availabe_offers( $post_id, Merchant_Pro_Frequently_Bought_Together::bundles() );
806
807 if ( ! empty( $bundle_data ) ) {
808 $bundles[ $post_id ] = Merchant_Pro_Frequently_Bought_Together::map_bundles( $bundle_data );
809 }
810
811 if ( ! empty( $bundles ) ) {
812 merchant_get_template_part(
813 Merchant_Frequently_Bought_Together::MODULE_TEMPLATES_PATH,
814 'single-product',
815 array(
816 'bundles' => $bundles,
817 'nonce' => wp_create_nonce( Merchant_Pro_Frequently_Bought_Together::AJAX_NONCE_ACTION ),
818 'settings' => Merchant_Admin_Options::get_all( Merchant_Frequently_Bought_Together::MODULE_ID ),
819 )
820 );
821 }
822 }
823
824 /**
825 * Custom CSS.
826 *
827 * @return string
828 */
829 public function get_module_custom_css() {
830 $css = '';
831
832 // Button Icon Color.
833 $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'icon-color', '#ffffff', '.merchant-quick-view-button', '--mrc-qv-button-icon-color' );
834
835 // Button Icon Color (hover).
836 $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'icon-hover-color', '#ffffff', '.merchant-quick-view-button', '--mrc-qv-button-icon-color-hover' );
837
838 // Button Text Color.
839 $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'text-color', '#ffffff', '.merchant-quick-view-button', '--mrc-qv-button-text-color' );
840
841 // Button Text Color (hover).
842 $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'text-hover-color', '#ffffff', '.merchant-quick-view-button', '--mrc-qv-button-text-color-hover' );
843
844 // Button Border Color.
845 $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'border-color', '#212121', '.merchant-quick-view-button', '--mrc-qv-button-border-color' );
846
847 // Button Border Color (hover).
848 $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'border-hover-color', '#414141', '.merchant-quick-view-button', '--mrc-qv-button-border-color-hover' );
849
850 // Button Background Color.
851 $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'background-color', '#212121', '.merchant-quick-view-button', '--mrc-qv-button-bg-color' );
852
853 // Button Background Color (hover).
854 $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'background-hover-color', '#414141', '.merchant-quick-view-button', '--mrc-qv-button-bg-color-hover' );
855
856 // Button Position Top.
857 $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'button-position-top', '50', '.merchant-quick-view-button', '--mrc-qv-button-position-top', '%' );
858
859 // Button Position Top (Mobile).
860 $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'button-position-top-mobile', '50', '.merchant-quick-view-button', '--mrc-qv-button-position-top-mobile', '%' );
861
862 // Button Position Left.
863 $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'button-position-left', '50', '.merchant-quick-view-button', '--mrc-qv-button-position-left', '%' );
864
865 // Button Position Left (Mobile).
866 $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'button-position-left-mobile', '50', '.merchant-quick-view-button', '--mrc-qv-button-position-left-mobile', '%' );
867
868 // Modal Width.
869 $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'modal_width', 1000, '.merchant-quick-view-modal', '--mrc-qv-modal-width', 'px' );
870
871 // Modal Height.
872 $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'modal_height', 500, '.merchant-quick-view-modal', '--mrc-qv-modal-height', 'px' );
873
874 // Sale Price Color.
875 $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'sale-price-color', '#212121', '.merchant-quick-view-modal', '--mrc-qv-modal-sale-price-color' );
876
877 // Regular Price Color.
878 $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'regular-price-color', '#414141', '.merchant-quick-view-modal', '--mrc-qv-modal-regular-price-color' );
879
880 return $css;
881 }
882
883 /**
884 * Admin custom CSS.
885 *
886 * @param string $css The custom CSS.
887 * @return string $css The custom CSS.
888 */
889 public function admin_custom_css( $css ) {
890 $css .= $this->get_module_custom_css();
891
892 return $css;
893 }
894
895 /**
896 * Frontend custom CSS.
897 *
898 * @param string $css The custom CSS.
899 * @return string $css The custom CSS.
900 */
901 public function frontend_custom_css( $css ) {
902 $css .= $this->get_module_custom_css();
903
904 $theme = wp_get_theme();
905 $theme_name = $theme->get( 'Name' );
906
907 if ( 'Astra' === $theme_name ) {
908 $css .= '
909 .astra-shop-thumbnail-wrap {
910 position: relative;
911 }
912 .astra-shop-thumbnail-wrap img {
913 width: 100%;
914 }
915 ';
916 }
917
918 if ( 'Storefront' === $theme_name ) {
919 $css .= '
920 .merchant-storefront-thumbnail-wrapper {
921 position: relative;
922 }
923 ';
924 }
925
926 return $css;
927 }
928 }
929
930 // Initialize the module.
931 add_action( 'init', function() {
932 Merchant_Quick_View::get_instance();
933 } );
934