PluginProbe
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant / 2.3.2
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant v2.3.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
← All changes | inc/modules/quick-view/class-quick-view.php +266 -203 1.10.02.3.2 View file →
@@ -22,16 +22,38 @@
22 22 */
23 23 const MODULE_ID = 'quick-view';
24 24
25 25 /**
26 + * Module templates path.
27 + *
28 + */
29 + const MODULE_TEMPLATES = 'modules/' . self::MODULE_ID;
30 +
31 + /**
26 32 * Is module preview.
27 33 *
28 34 */
29 35 public static $is_module_preview = false;
30 36
37 + /**
38 + * Whether the module has a shortcode or not.
39 + *
40 + * @var bool
41 + */
42 + public $has_shortcode = true;
43 +
31 44 private static $instance = null;
32 45
33 46 /**
47 + * Initialize the module's option group definitions.
48 + *
49 + * @return array<int, array<string, mixed>> Array of option group arrays.
50 + */
51 + protected function init_option_groups() {
52 + return require MERCHANT_DIR . 'inc/modules/' . self::MODULE_ID . '/admin/options.php';
53 + }
54 +
55 + /**
34 56 * Constructor.
35 57 *
36 58 */
37 59 public function __construct() {
@@ -55,8 +77,14 @@
55 77 'button_icon' => 'eye',
56 78 'button_position' => 'overlay',
57 79 'button-position-top' => 50,
58 80 'button-position-left' => 50,
81 + 'mobile_position' => false,
82 + 'button-position-top-mobile' => 50,
83 + 'button-position-left-mobile' => 50,
84 + 'modal_layout' => 'modal',
85 + 'show_navigation_arrows' => 0,
86 + 'sync_url_hash' => 0,
59 87 'zoom_effect' => 1,
60 88 'show_quantity' => 1,
61 89 'place_product_description' => 'top',
62 90 'description_style' => 'short',
@@ -66,19 +94,22 @@
66 94 'suggested_products_module' => 'bulk_discounts',
67 95 'suggested_products_placement' => 'after_add_to_cart',
68 96 );
69 97
70 - // Mount preview url.
71 - $preview_url = site_url( '/' );
72 -
73 - if ( function_exists( 'wc_get_page_id' ) ) {
74 - $preview_url = get_permalink( wc_get_page_id( 'shop' ) );
75 - }
76 -
77 98 // Module data.
78 99 $this->module_data = Merchant_Admin_Modules::$modules_data[ self::MODULE_ID ];
79 - $this->module_data[ 'preview_url' ] = $preview_url;
80 100
101 + // AI prompt examples.
102 + $this->ai_examples = array(
103 + 'blurb' => esc_html__( 'See what AI can do for your Quick View popup, from restyling the button to rearranging what shows inside the modal.', 'merchant' ),
104 + 'prompts' => array(
105 + esc_html__( "Explore the abilities WPVibe gives you access to, then set the Quick View button to show an icon and text, label it 'View Details', and use the cart icon", 'merchant' ),
106 + esc_html__( 'Check what abilities you have available through WPVibe, then overlay the Quick View button (labeled View Details) on the product image, positioned 20% from the top and 80% from the left', 'merchant' ),
107 + esc_html__( 'Look at your available WPVibe abilities, then widen the quick view modal to 1200px, move the gallery thumbnails to the bottom, and show the full product description', 'merchant' ),
108 + esc_html__( 'See what abilities WPVibe exposes, then enable ajax add to cart in the quick view popup and hide the quantity selector', 'merchant' ),
109 + ),
110 + );
111 +
81 112 // Module options path.
82 113 $this->module_options_path = MERCHANT_DIR . 'inc/modules/' . self::MODULE_ID . '/admin/options.php';
83 114
84 115 // Is module preview page.
@@ -107,9 +138,9 @@
107 138 }
108 139
109 140 // Return early if it's on admin but not in the respective module settings page.
110 141 if ( is_admin() && ! wp_doing_ajax() && ! parent::is_module_settings_page() ) {
111 - return;
142 + return;
112 143 }
113 144
114 145 // Enqueue styles.
115 146 add_action( 'merchant_enqueue_before_main_css_js', array( $this, 'enqueue_css' ) );
@@ -125,21 +156,42 @@
125 156 add_action( 'wp_enqueue_scripts', array( $this, 'modal_compatibility_with_botiga_theme' ) );
126 157 }
127 158
128 159 // Button Position.
129 - $button_position = Merchant_Admin_Options::get( self::MODULE_ID, 'button_position', 'overlay' );
160 + if ( ! $this->is_shortcode_enabled() ) {
161 + $button_position = Merchant_Admin_Options::get( self::MODULE_ID, 'button_position', 'overlay' );
130 162
131 - if ( 'before' === $button_position ) {
132 - add_action( 'woocommerce_after_shop_loop_item', array( $this, 'quick_view_button' ), 5 );
133 - } elseif ( 'after' === $button_position ) {
134 - add_action( 'woocommerce_after_shop_loop_item', array( $this, 'quick_view_button' ), 15 );
135 - } elseif ( 'overlay' === $button_position ) {
136 - if ( merchant_is_kadence_active() ) {
137 - add_filter( 'kadence_archive_content_wrap_start', array( $this, 'add_quick_view_button' ) );
138 - } else {
139 - add_action( 'woocommerce_after_shop_loop_item', array( $this, 'quick_view_button' ), 15 );
140 - }
141 - }
163 + if ( 'before' === $button_position ) {
164 + add_action( 'woocommerce_after_shop_loop_item', array( $this, 'quick_view_button' ), 5 );
165 + } elseif ( 'after' === $button_position ) {
166 + add_action( 'woocommerce_after_shop_loop_item', array( $this, 'quick_view_button' ), 15 );
167 + } elseif ( 'overlay' === $button_position ) {
168 + if ( merchant_is_kadence_active() ) {
169 + add_action( 'woocommerce_before_shop_loop_item_title', array( $this, 'quick_view_button' ), 35 );
170 + //add_filter( 'kadence_archive_content_wrap_start', array( $this, 'add_quick_view_button' ) );
171 + } elseif ( merchant_is_blocksy_active() ) {
172 + add_action( 'blocksy:woocommerce:product-card:thumbnail:end', array( $this, 'quick_view_button' ) );
173 + } elseif ( merchant_is_botiga_active() ) {
174 + add_action( 'woocommerce_before_shop_loop_item_title', array( $this, 'quick_view_button' ) );
175 + } elseif ( merchant_is_oceanwp_active() ) {
176 + add_action( 'ocean_after_archive_product_image', array( $this, 'quick_view_button' ) );
177 + } elseif ( merchant_is_flatsome_active() ) {
178 + add_action( 'flatsome_woocommerce_shop_loop_images', array( $this, 'quick_view_button' ) );
179 + } elseif ( merchant_is_storefront_active() ) {
180 + remove_action( 'woocommerce_before_shop_loop_item_title', 'woocommerce_template_loop_product_thumbnail', 10 );
181 + add_action( 'woocommerce_before_shop_loop_item_title', function () {
182 + echo '<div class="merchant-storefront-thumbnail-wrapper">';
183 + woocommerce_template_loop_product_thumbnail();
184 + $this->quick_view_button();
185 + echo '</div>';
186 + } );
187 + } elseif ( merchant_is_astra_active() ) {
188 + add_action( 'woocommerce_after_shop_loop_item', array( $this, 'quick_view_button' ), 7 );
189 + } else {
190 + add_action( 'woocommerce_after_shop_loop_item', array( $this, 'quick_view_button' ) );
191 + }
192 + }
193 + }
142 194
143 195 // Inject quick view modal output on footer.
144 196 add_action( 'wp_footer', array( $this, 'modal_output' ) );
145 197
@@ -146,8 +198,12 @@
146 198 // Show Suggested Module
147 199 $suggested_placement = Merchant_Admin_Options::get( self::MODULE_ID, 'suggested_products_placement', 'after_add_to_cart' );
148 200 add_action( 'merchant_quick_view_' . $suggested_placement, array( $this, 'render_suggested_module_content' ), 10, 2 );
149 201
202 + // Let other modules (e.g. Pro asset managers) ask which suggested-products
203 + // module is active without depending on Quick View's own option keys.
204 + add_filter( 'merchant_quick_view_suggested_products_module', array( $this, 'get_active_suggested_products_module' ) );
205 +
150 206 // Show Buy Now Module
151 207 add_action( 'woocommerce_after_add_to_cart_button', array( $this, 'render_buy_now_button' ) );
152 208
153 209 // Custom CSS.
@@ -155,11 +211,27 @@
155 211
156 212 // Modal content ajax callback.
157 213 add_action( 'wp_ajax_merchant_quick_view_content', array( $this, 'modal_content_ajax_callback' ) );
158 214 add_action( 'wp_ajax_nopriv_merchant_quick_view_content', array( $this, 'modal_content_ajax_callback' ) );
215 +
216 + // Initialize AJAX add to cart handler (separate class).
217 + $this->init_ajax_add_to_cart();
159 218 }
160 219
220 + /**
221 + * Initialize AJAX add to cart functionality.
222 + *
223 + * @return void
224 + */
225 + private function init_ajax_add_to_cart() {
226 + Merchant_Quick_View_Ajax_Add_To_Cart::get_instance()->init();
227 + }
161 228
229 + /**
230 + * Singleton
231 + *
232 + * @return self|null
233 + */
162 234 public static function get_instance() {
163 235 if ( self::$instance === null ) {
164 236 self::$instance = new self();
165 237 }
@@ -179,8 +251,44 @@
179 251 }
180 252 }
181 253
182 254 /**
255 + * Print shortcode content.
256 + *
257 + * @return string
258 + */
259 + public function shortcode_handler() {
260 + // Check if module is active.
261 + if ( ! Merchant_Modules::is_module_active( $this->module_id ) ) {
262 + return '';
263 + }
264 +
265 + // Check if shortcode is enabled.
266 + if ( ! $this->is_shortcode_enabled() ) {
267 + return '';
268 + }
269 +
270 + global $product;
271 +
272 + $product_id = is_object( $product ) ? $product->get_id() : get_the_ID();
273 +
274 + ob_start();
275 + $this->quick_view_button( 'shortcode' );
276 + $shortcode_content = ob_get_clean();
277 +
278 + /**
279 + * Filter the shortcode html content.
280 + *
281 + * @param string $shortcode_content shortcode html content
282 + * @param string $module_id module id
283 + * @param int $post_id product id
284 + *
285 + * @since 1.8
286 + */
287 + return apply_filters( 'merchant_module_shortcode_content_html', $shortcode_content, $this->module_id, $product_id );
288 + }
289 +
290 + /**
183 291 * Concatenate the quick view button with the content start wrap.
184 292 *
185 293 * @return string
186 294 */
@@ -219,10 +327,15 @@
219 327 *
220 328 * @return void
221 329 */
222 330 public function enqueue_scripts() {
223 - wp_enqueue_script( 'zoom' );
224 - wp_enqueue_script( 'flexslider' );
331 + if ( defined( 'WC_VERSION' ) && version_compare( WC_VERSION, '10.3', '>=' ) ) {
332 + wp_enqueue_script( 'wc-zoom' );
333 + wp_enqueue_script( 'wc-flexslider' );
334 + } else {
335 + wp_enqueue_script( 'zoom' );
336 + wp_enqueue_script( 'flexslider' );
337 + }
225 338 wp_enqueue_script( 'wc-single-product' );
226 339 wp_enqueue_script( 'wc-add-to-cart-variation' );
227 340
228 341 // Register and enqueue the main module script.
@@ -237,10 +350,12 @@
237 350 */
238 351 public function localize_script( $setting ) {
239 352 $module_settings = $this->get_module_settings();
240 353
241 - $setting[ 'quick_view' ] = true;
242 - $setting[ 'quick_view_zoom' ] = $module_settings[ 'zoom_effect' ];
354 + $setting[ 'quick_view' ] = true;
355 + $setting[ 'quick_view_zoom' ] = $module_settings[ 'zoom_effect' ];
356 + $setting[ 'ajax_add_to_cart' ] = ! empty( $module_settings[ 'ajax_add_to_cart' ] );
357 + $setting[ 'sync_url_hash' ] = ! empty( $module_settings[ 'sync_url_hash' ] );
243 358
244 359 return $setting;
245 360 }
246 361
@@ -357,11 +472,10 @@
357 472 }
358 473
359 474 /**
360 475 * Modal content ajax callback.
361 - * TODO: Render the output through templates files.
362 - *
363 - * @return void
476 + *
477 + * @return void
364 478 */
365 479 public function modal_content_ajax_callback() {
366 480 check_ajax_referer( 'merchant-nonce', 'nonce' );
367 481
@@ -372,9 +486,9 @@
372 486 $args = array(
373 487 'product_id' => absint( $_POST['product_id'] ),
374 488 );
375 489
376 - global $product;
490 + global $product, $post;
377 491
378 492 $settings = $this->get_module_settings();
379 493 $product = wc_get_product( $args['product_id'] );
380 494
@@ -381,174 +495,37 @@
381 495 if ( is_wp_error( $product ) || empty( $product ) ) {
382 496 wp_send_json_error();
383 497 }
384 498
385 - $product_id = $product->get_id();
386 - $hide_quantity = ( empty( $settings[ 'show_quantity' ] ) ) ? 'merchant-hide-quantity' : '';
499 + // Mirror the real single-product page's main-query post so functions like
500 + // `get_the_ID()` (used by other modules hooking into `merchant_quick_view_product_summary`,
501 + // e.g. Payment Logos' exclusion checks) resolve correctly during this AJAX request.
502 + $post = get_post( $args['product_id'] ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
387 503
388 - ob_start();
389 - ?>
390 - <div id="product-<?php echo absint( $product_id ); ?>" <?php wc_product_class( '', $product ); ?>>
391 - <div class="merchant-quick-view-row">
392 - <div class="merchant-quick-view-column">
393 - <div class="merchant-quick-view-product-gallery">
394 - <?php woocommerce_show_product_images(); ?>
395 - </div>
396 - </div>
504 + $content = merchant_get_template_part(
505 + self::MODULE_TEMPLATES,
506 + 'content',
507 + array(
508 + 'product' => $product,
509 + 'settings' => $settings,
510 + ),
511 + true
512 + );
397 513
398 - <div class="merchant-quick-view-column">
399 - <div class="merchant-quick-view-summary product-gallery-summary">
400 - <div class="merchant-quick-view-product-title">
401 - <h2 class="product_title entry-title"><?php echo esc_html( $product->get_title() ); ?></h2>
402 - </div>
403 -
404 - <?php if ( 0 !== $product->get_average_rating() ) : ?>
405 - <div class="merchant-quick-view-product-rating">
406 - <div class="woocommerce-product-rating">
407 - <?php echo wp_kses( wc_get_rating_html( $product->get_average_rating() ), merchant_kses_allowed_tags() ); ?>
408 - </div>
409 - </div>
410 - <?php endif; ?>
411 -
412 - <div class="merchant-quick-view-product-price">
413 - <div class="price"><?php echo wp_kses( $product->get_price_html(), merchant_kses_allowed_tags() ); ?></div>
414 - </div>
415 -
416 - <?php if ( 'top' === $settings[ 'place_product_description' ] ) : ?>
417 - <?php
418 - /**
419 - * Hook 'merchant_quick_view_before_product_description'
420 - *
421 - * @since 1.9.14
422 - */
423 - do_action( 'merchant_quick_view_before_product_description' );
424 -
425 - $description = $settings[ 'description_style' ] === 'full' ? $product->get_description() : $product->get_short_description();
426 -
427 - /**
428 - * `merchant_quick_view_description`
429 - *
430 - * @since 1.9.16
431 - */
432 - $description = apply_filters( 'merchant_quick_view_description', $description );
433 - ?>
434 - <div class="merchant-quick-view-product-excerpt">
435 - <?php echo wp_kses_post( $description ); ?>
436 - </div>
437 -
438 - <?php
439 - /**
440 - * Hook 'merchant_quick_view_before_product_description'
441 - *
442 - * @since 1.9.14
443 - */
444 - do_action( 'merchant_quick_view_after_product_description' );
445 - ?>
446 - <?php endif; ?>
447 -
448 - <?php
449 - /**
450 - * Hook 'merchant_quick_view_before_add_to_cart'
451 - *
452 - * @since 1.9.14
453 - */
454 - do_action( 'merchant_quick_view_before_add_to_cart', $product, $settings );
455 - ?>
456 - <div class="merchant-quick-view-product-add-to-cart <?php echo esc_attr( $hide_quantity ); ?>">
457 - <?php woocommerce_template_single_add_to_cart(); ?>
458 - </div>
459 -
460 - <?php
461 - /**
462 - * Hook 'merchant_quick_view_after_add_to_cart'
463 - *
464 - * @since 1.9.14
465 - */
466 - do_action( 'merchant_quick_view_after_add_to_cart', $product, $settings );
467 - ?>
468 -
469 - <?php if ( 'bottom' === $settings[ 'place_product_description' ] ) : ?>
470 - <?php
471 - /**
472 - * Hook 'merchant_quick_view_before_product_description'
473 - *
474 - * @since 1.9.14
475 - */
476 - do_action( 'merchant_quick_view_before_product_description' );
477 -
478 - $description = $settings[ 'description_style' ] === 'full' ? $product->get_description() : $product->get_short_description();
479 -
480 - /**
481 - * `merchant_quick_view_description`
482 - *
483 - * @since 1.9.16
484 - */
485 - $description = apply_filters( 'merchant_quick_view_description', $description );
486 - ?>
487 - <div class="merchant-quick-view-product-excerpt">
488 - <?php echo wp_kses_post( $description ); ?>
489 - </div>
490 -
491 - <?php
492 - /**
493 - * Hook 'merchant_quick_view_after_product_description'
494 - *
495 - * @since 1.9.14
496 - */
497 - do_action( 'merchant_quick_view_after_product_description' );
498 - ?>
499 - <?php endif; ?>
500 - <div class="merchant-quick-view-product-meta">
501 - <?php woocommerce_template_single_meta(); ?>
502 - </div>
503 -
504 - <?php
505 - /**
506 - * Hook 'merchant_quick_view_after_product_excerpt'
507 - *
508 - * @since 1.0.0
509 - */
510 - do_action( 'merchant_quick_view_after_product_meta' );
511 - ?>
512 - </div>
513 - </div>
514 - </div>
515 - </div>
516 - <?php
517 - $content = ob_get_contents();
518 -
519 - ob_get_clean();
520 -
521 514 wp_send_json_success( $content );
522 515 }
523 516
517 +
524 518 /**
525 519 * Modal output.
526 - * TODO: Render the output through templates files.
527 - *
520 + *
528 521 * @return void
529 522 */
530 523 public function modal_output() {
531 524 $settings = $this->get_module_settings();
532 - ?>
533 - <div class="single-product merchant-quick-view-modal merchant-quick-view-<?php echo esc_attr( $settings[ 'place_product_image' ] ); ?>">
534 - <div class="merchant-quick-view-overlay"></div>
535 - <div class="merchant-quick-view-loader">
536 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
537 - <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" />
538 - <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" />
539 - </svg>
540 - </div>
541 - <div class="merchant-quick-view-inner">
542 - <a href="#" class="merchant-quick-view-close-button" title="<?php echo esc_attr__( 'Close quick view modal', 'merchant' ); ?>">
543 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
544 - <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"/>
545 - </svg>
546 - </a>
547 - <div class="merchant-quick-view-content"></div>
548 - </div>
549 - </div>
550 - <?php
525 + $template = ( 'side-panel' === $settings[ 'modal_layout' ] ) ? 'side-panel' : 'modal';
526 +
527 + merchant_get_template_part( self::MODULE_TEMPLATES, $template, array( 'settings' => $settings ) );
551 528 }
552 529
553 530 /**
554 531 * Quick view button.
@@ -554,11 +531,15 @@
554 531 * Quick view button.
555 532 *
556 533 * @return void
557 534 */
558 - public function quick_view_button() {
535 + public function quick_view_button( $context = '' ) {
559 536 global $product;
560 537
538 + if ( ! is_object( $product ) ) {
539 + return;
540 + }
541 +
561 542 $settings = $this->get_module_settings();
562 543 $product_id = $product->get_id();
563 544
564 545 $button_text_html = '';
@@ -571,10 +552,15 @@
571 552 if ( 'text' === $settings[ 'button_type' ] || 'icon-text' === $settings[ 'button_type' ] ) {
572 553 $button_text_html = '<span>' . Merchant_Translator::translate( $settings[ 'button_text' ] ) . '</span>';
573 554 }
574 555
556 + $classes = 'button wp-element-button merchant-quick-view-button';
557 + $classes .= $context !== 'shortcode' ? ' merchant-quick-view-position-' . ( $settings[ 'button_position' ] ?? '' ) : '';
558 + $classes .= ( $context !== 'shortcode' && ! empty( $settings['mobile_position'] ) ) ? ' merchant-quick-view-position-has-mobile-position' : '';
575 559 ?>
576 - <a href="#" class="button wp-element-button merchant-quick-view-button merchant-quick-view-position-<?php echo esc_attr( $settings[ 'button_position' ] ); ?>" data-product-id="<?php echo absint( $product_id ); ?>"><?php echo wp_kses( $button_icon_html, merchant_kses_allowed_tags( array(), false ) ) . wp_kses_post( $button_text_html ); ?></a>
560 + <button class="<?php echo esc_attr( $classes ); ?>" data-product-id="<?php echo absint( $product_id ); ?>" type="button">
561 + <?php echo wp_kses( $button_icon_html, merchant_kses_allowed_tags( array(), false ) ) . wp_kses_post( $button_text_html ); ?>
562 + </button>
577 563 <?php
578 564 }
579 565
580 566 /**
@@ -598,8 +584,23 @@
598 584 }
599 585
600 586 global $product;
601 587
588 + /**
589 + * Filters whether the Buy Now button should be excluded for a specific product in Quick View.
590 + *
591 + * This filter allows modules (like Buy Now) to control the visibility of the Buy Now button
592 + * in the Quick View modal based on their own exclusion rules.
593 + *
594 + * @param bool $is_excluded Whether the product is excluded. Default false.
595 + * @param WC_Product $product The product object.
596 + *
597 + * @since 2.2.4
598 + */
599 + if ( apply_filters( 'merchant_buy_now_is_excluded', false, $product ) ) {
600 + return;
601 + }
602 +
602 603 $text = Merchant_Admin_Options::get( Merchant_Buy_Now::MODULE_ID, 'button-text', esc_html__( 'Buy Now', 'merchant' ) );
603 604
604 605 $_wrapper_classes = array();
605 606 $_wrapper_classes[] = $product->get_type() === 'variable' ? 'disabled' : '';
@@ -648,8 +649,27 @@
648 649 }
649 650 }
650 651
651 652 /**
653 + * Gets the currently configured suggested-products module.
654 + *
655 + * Filter callback for `merchant_quick_view_suggested_products_module`, so
656 + * other modules can check which module is active without reading Quick
657 + * View's option keys directly.
658 + *
659 + * @param string|false $default_value Default value passed through the filter.
660 + *
661 + * @return string|false The active module slug, or false if suggested products are disabled.
662 + */
663 + public function get_active_suggested_products_module( $default_value = false ) {
664 + if ( ! Merchant_Admin_Options::get( self::MODULE_ID, 'show_suggested_products', true ) ) {
665 + return false;
666 + }
667 +
668 + return Merchant_Admin_Options::get( self::MODULE_ID, 'suggested_products_module', 'bulk_discounts' );
669 + }
670 +
671 + /**
652 672 * Prints the bulk discounts for the specified product.
653 673 *
654 674 * @param $product
655 675 *
@@ -691,10 +711,16 @@
691 711 if ( ! merchant_is_pro_active() || ! Merchant_Modules::is_module_active( Merchant_Buy_X_Get_Y::MODULE_ID ) ) {
692 712 return;
693 713 }
694 714
715 + $eligibility = Merchant_Pro_BXGY_Service_Provider::eligibility();
716 +
717 + if ( ! $eligibility ) {
718 + return;
719 + }
720 +
695 721 $product_id = $product->get_id();
696 - $offers = Merchant_Pro_Buy_X_Get_Y::availabe_offers( $product_id );
722 + $offers = $eligibility->get_eligible_for_product( $product_id );
697 723
698 724 if ( ! empty( $offers ) ) {
699 725 merchant_get_template_part(
700 726 Merchant_Buy_X_Get_Y::MODULE_TEMPLATES,
@@ -699,12 +725,13 @@
699 725 merchant_get_template_part(
700 726 Merchant_Buy_X_Get_Y::MODULE_TEMPLATES,
701 727 'single-product',
702 728 array(
703 - 'offers' => $offers,
704 - 'nonce' => wp_create_nonce( 'merchant_bogo_add_to_cart' ),
705 - 'settings' => Merchant_Admin_Options::get_all( Merchant_Buy_X_Get_Y::MODULE_ID ),
706 - 'product' => $product_id,
729 + 'offers' => $offers,
730 + 'nonce' => wp_create_nonce( 'merchant_bogo_add_to_cart' ),
731 + 'settings' => Merchant_Admin_Options::get_all( Merchant_Buy_X_Get_Y::MODULE_ID ),
732 + 'product' => $product_id,
733 + 'module_id' => Merchant_Buy_X_Get_Y::MODULE_ID,
707 734 )
708 735 );
709 736 }
710 737 }
@@ -720,23 +747,24 @@
720 747 if ( ! merchant_is_pro_active() || ! Merchant_Modules::is_module_active( Merchant_Frequently_Bought_Together::MODULE_ID ) ) {
721 748 return;
722 749 }
723 750
724 - $post_id = $product->get_id();
725 - $bundle_data = Merchant_Pro_Frequently_Bought_Together::availabe_offers( $post_id, Merchant_Pro_Frequently_Bought_Together::bundles() );
751 + $post_id = $product->get_id();
752 + $repository = new Merchant_Pro_FBT_Offer_Repository( Merchant_Frequently_Bought_Together::MODULE_ID );
753 + $price_calc = new Merchant_Pro_FBT_Price_Calculator( Merchant_Frequently_Bought_Together::MODULE_ID );
754 + $bundle_mapper = new Merchant_Pro_FBT_Bundle_Mapper( $price_calc );
755 + $offer_resolver = new Merchant_Pro_FBT_Offer_Resolver( $repository, $bundle_mapper );
756 + $bundles = $offer_resolver->available_offers( $post_id );
726 757
727 - if ( ! empty( $bundle_data ) ) {
728 - $bundles[ $post_id ] = Merchant_Pro_Frequently_Bought_Together::map_bundles( $bundle_data );
729 - }
730 -
731 758 if ( ! empty( $bundles ) ) {
732 759 merchant_get_template_part(
733 760 Merchant_Frequently_Bought_Together::MODULE_TEMPLATES_PATH,
734 - 'single-product',
761 + 'single-product-v3',
735 762 array(
736 - 'bundles' => $bundles,
737 - 'nonce' => wp_create_nonce( Merchant_Pro_Frequently_Bought_Together::AJAX_NONCE_ACTION ),
738 - 'settings' => Merchant_Admin_Options::get_all( Merchant_Frequently_Bought_Together::MODULE_ID ),
763 + 'bundle' => reset( $bundles ),
764 + 'nonce' => wp_create_nonce( Merchant_Pro_Frequently_Bought_Together::AJAX_NONCE_ACTION ),
765 + 'settings' => Merchant_Admin_Options::get_all( Merchant_Frequently_Bought_Together::MODULE_ID ),
766 + 'module_id' => Merchant_Frequently_Bought_Together::MODULE_ID,
739 767 )
740 768 );
741 769 }
742 770 }
@@ -775,11 +803,17 @@
775 803
776 804 // Button Position Top.
777 805 $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'button-position-top', '50', '.merchant-quick-view-button', '--mrc-qv-button-position-top', '%' );
778 806
807 + // Button Position Top (Mobile).
808 + $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'button-position-top-mobile', '50', '.merchant-quick-view-button', '--mrc-qv-button-position-top-mobile', '%' );
809 +
779 810 // Button Position Left.
780 811 $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'button-position-left', '50', '.merchant-quick-view-button', '--mrc-qv-button-position-left', '%' );
781 -
812 +
813 + // Button Position Left (Mobile).
814 + $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'button-position-left-mobile', '50', '.merchant-quick-view-button', '--mrc-qv-button-position-left-mobile', '%' );
815 +
782 816 // Modal Width.
783 817 $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'modal_width', 1000, '.merchant-quick-view-modal', '--mrc-qv-modal-width', 'px' );
784 818
785 819 // Modal Height.
@@ -784,8 +818,11 @@
784 818
785 819 // Modal Height.
786 820 $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'modal_height', 500, '.merchant-quick-view-modal', '--mrc-qv-modal-height', 'px' );
787 821
822 + // Side Panel Width.
823 + $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'side_panel_width', 420, '.merchant-quick-view-modal', '--mrc-qv-panel-width', 'px' );
824 +
788 825 // Sale Price Color.
789 826 $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'sale-price-color', '#212121', '.merchant-quick-view-modal', '--mrc-qv-modal-sale-price-color' );
790 827
791 828 // Regular Price Color.
@@ -814,8 +851,30 @@
814 851 */
815 852 public function frontend_custom_css( $css ) {
816 853 $css .= $this->get_module_custom_css();
817 854
855 + $theme = wp_get_theme();
856 + $theme_name = $theme->get( 'Name' );
857 +
858 + if ( 'Astra' === $theme_name ) {
859 + $css .= '
860 + .astra-shop-thumbnail-wrap {
861 + position: relative;
862 + }
863 + .astra-shop-thumbnail-wrap img {
864 + width: 100%;
865 + }
866 + ';
867 + }
868 +
869 + if ( 'Storefront' === $theme_name ) {
870 + $css .= '
871 + .merchant-storefront-thumbnail-wrapper {
872 + position: relative;
873 + }
874 + ';
875 + }
876 +
818 877 return $css;
819 878 }
820 879 }
821 880
@@ -820,6 +879,10 @@
820 879 }
821 880
822 881 // Initialize the module.
823 882 add_action( 'init', function() {
824 - Merchant_Quick_View::get_instance();
883 + // Load AJAX add to cart class file.
884 + require_once MERCHANT_DIR . 'inc/modules/quick-view/class-quick-view-ajax-add-to-cart.php';
885 +
886 + // Create and initialize the module.
887 + Merchant_Modules::create_module( Merchant_Quick_View::get_instance() );
825 888 } );