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 +99 -174 2.2.72.3.2 View file →
@@ -22,8 +22,14 @@
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;
@@ -37,8 +43,17 @@
37 43
38 44 private static $instance = null;
39 45
40 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 + /**
41 56 * Constructor.
42 57 *
43 58 */
44 59 public function __construct() {
@@ -65,8 +80,11 @@
65 80 'button-position-left' => 50,
66 81 'mobile_position' => false,
67 82 'button-position-top-mobile' => 50,
68 83 'button-position-left-mobile' => 50,
84 + 'modal_layout' => 'modal',
85 + 'show_navigation_arrows' => 0,
86 + 'sync_url_hash' => 0,
69 87 'zoom_effect' => 1,
70 88 'show_quantity' => 1,
71 89 'place_product_description' => 'top',
72 90 'description_style' => 'short',
@@ -79,8 +97,19 @@
79 97
80 98 // Module data.
81 99 $this->module_data = Merchant_Admin_Modules::$modules_data[ self::MODULE_ID ];
82 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 +
83 112 // Module options path.
84 113 $this->module_options_path = MERCHANT_DIR . 'inc/modules/' . self::MODULE_ID . '/admin/options.php';
85 114
86 115 // Is module preview page.
@@ -169,8 +198,12 @@
169 198 // Show Suggested Module
170 199 $suggested_placement = Merchant_Admin_Options::get( self::MODULE_ID, 'suggested_products_placement', 'after_add_to_cart' );
171 200 add_action( 'merchant_quick_view_' . $suggested_placement, array( $this, 'render_suggested_module_content' ), 10, 2 );
172 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 +
173 206 // Show Buy Now Module
174 207 add_action( 'woocommerce_after_add_to_cart_button', array( $this, 'render_buy_now_button' ) );
175 208
176 209 // Custom CSS.
@@ -320,8 +353,9 @@
320 353
321 354 $setting[ 'quick_view' ] = true;
322 355 $setting[ 'quick_view_zoom' ] = $module_settings[ 'zoom_effect' ];
323 356 $setting[ 'ajax_add_to_cart' ] = ! empty( $module_settings[ 'ajax_add_to_cart' ] );
357 + $setting[ 'sync_url_hash' ] = ! empty( $module_settings[ 'sync_url_hash' ] );
324 358
325 359 return $setting;
326 360 }
327 361
@@ -438,11 +472,10 @@
438 472 }
439 473
440 474 /**
441 475 * Modal content ajax callback.
442 - * TODO: Render the output through templates files.
443 - *
444 - * @return void
476 + *
477 + * @return void
445 478 */
446 479 public function modal_content_ajax_callback() {
447 480 check_ajax_referer( 'merchant-nonce', 'nonce' );
448 481
@@ -453,9 +486,9 @@
453 486 $args = array(
454 487 'product_id' => absint( $_POST['product_id'] ),
455 488 );
456 489
457 - global $product;
490 + global $product, $post;
458 491
459 492 $settings = $this->get_module_settings();
460 493 $product = wc_get_product( $args['product_id'] );
461 494
@@ -462,144 +495,23 @@
462 495 if ( is_wp_error( $product ) || empty( $product ) ) {
463 496 wp_send_json_error();
464 497 }
465 498
466 - $product_id = $product->get_id();
467 - $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
468 503
469 - ob_start();
470 - ?>
471 - <div id="product-<?php echo absint( $product_id ); ?>" <?php wc_product_class( '', $product ); ?>>
472 - <div class="merchant-quick-view-row">
473 - <div class="merchant-quick-view-column">
474 - <div class="merchant-quick-view-product-gallery">
475 - <?php woocommerce_show_product_images(); ?>
476 - </div>
477 - </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 + );
478 513
479 - <div class="merchant-quick-view-column">
480 - <div class="merchant-quick-view-summary product-gallery-summary">
481 - <div class="merchant-quick-view-product-title">
482 - <h2 class="product_title entry-title"><?php echo esc_html( $product->get_title() ); ?></h2>
483 - </div>
484 -
485 - <?php if ( 0 !== $product->get_average_rating() ) : ?>
486 - <div class="merchant-quick-view-product-rating">
487 - <div class="woocommerce-product-rating">
488 - <?php echo wp_kses( wc_get_rating_html( $product->get_average_rating() ), merchant_kses_allowed_tags() ); ?>
489 - </div>
490 - </div>
491 - <?php endif; ?>
492 -
493 - <div class="merchant-quick-view-product-price">
494 - <div class="price"><?php echo wp_kses( $product->get_price_html(), merchant_kses_allowed_tags() ); ?></div>
495 - </div>
496 -
497 - <?php if ( 'top' === $settings[ 'place_product_description' ] ) : ?>
498 - <?php
499 - /**
500 - * Hook 'merchant_quick_view_before_product_description'
501 - *
502 - * @since 1.9.14
503 - */
504 - do_action( 'merchant_quick_view_before_product_description' );
505 -
506 - $description = $settings[ 'description_style' ] === 'full' ? $product->get_description() : $product->get_short_description();
507 -
508 - /**
509 - * `merchant_quick_view_description`
510 - *
511 - * @since 1.9.16
512 - */
513 - $description = apply_filters( 'merchant_quick_view_description', $description );
514 - ?>
515 - <div class="merchant-quick-view-product-excerpt">
516 - <?php echo wp_kses_post( do_shortcode( $description ) ); ?>
517 - </div>
518 -
519 - <?php
520 - /**
521 - * Hook 'merchant_quick_view_before_product_description'
522 - *
523 - * @since 1.9.14
524 - */
525 - do_action( 'merchant_quick_view_after_product_description' );
526 - ?>
527 - <?php endif; ?>
528 -
529 - <?php
530 - /**
531 - * Hook 'merchant_quick_view_before_add_to_cart'
532 - *
533 - * @since 1.9.14
534 - */
535 - do_action( 'merchant_quick_view_before_add_to_cart', $product, $settings );
536 - ?>
537 - <div class="merchant-quick-view-product-add-to-cart <?php echo esc_attr( $hide_quantity ); ?>">
538 - <?php woocommerce_template_single_add_to_cart(); ?>
539 - </div>
540 -
541 - <?php
542 - /**
543 - * Hook 'merchant_quick_view_after_add_to_cart'
544 - *
545 - * @since 1.9.14
546 - */
547 - do_action( 'merchant_quick_view_after_add_to_cart', $product, $settings );
548 - ?>
549 -
550 - <?php if ( 'bottom' === $settings[ 'place_product_description' ] ) : ?>
551 - <?php
552 - /**
553 - * Hook 'merchant_quick_view_before_product_description'
554 - *
555 - * @since 1.9.14
556 - */
557 - do_action( 'merchant_quick_view_before_product_description' );
558 -
559 - $description = $settings[ 'description_style' ] === 'full' ? $product->get_description() : $product->get_short_description();
560 -
561 - /**
562 - * `merchant_quick_view_description`
563 - *
564 - * @since 1.9.16
565 - */
566 - $description = apply_filters( 'merchant_quick_view_description', $description );
567 - ?>
568 - <div class="merchant-quick-view-product-excerpt">
569 - <?php echo wp_kses_post( do_shortcode( $description ) ); ?>
570 - </div>
571 -
572 - <?php
573 - /**
574 - * Hook 'merchant_quick_view_after_product_description'
575 - *
576 - * @since 1.9.14
577 - */
578 - do_action( 'merchant_quick_view_after_product_description' );
579 - ?>
580 - <?php endif; ?>
581 - <div class="merchant-quick-view-product-meta">
582 - <?php woocommerce_template_single_meta(); ?>
583 - </div>
584 -
585 - <?php
586 - /**
587 - * Hook 'merchant_quick_view_after_product_excerpt'
588 - *
589 - * @since 1.0.0
590 - */
591 - do_action( 'merchant_quick_view_after_product_meta' );
592 - ?>
593 - </div>
594 - </div>
595 - </div>
596 - </div>
597 - <?php
598 - $content = ob_get_contents();
599 -
600 - ob_get_clean();
601 -
602 514 wp_send_json_success( $content );
603 515 }
604 516
605 517
@@ -604,33 +516,16 @@
604 516
605 517
606 518 /**
607 519 * Modal output.
608 - * TODO: Render the output through templates files.
609 - *
520 + *
610 521 * @return void
611 522 */
612 523 public function modal_output() {
613 524 $settings = $this->get_module_settings();
614 - ?>
615 - <div class="single-product merchant-quick-view-modal merchant-quick-view-<?php echo esc_attr( $settings[ 'place_product_image' ] ); ?>">
616 - <div class="merchant-quick-view-overlay"></div>
617 - <div class="merchant-quick-view-loader">
618 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
619 - <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" />
620 - <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" />
621 - </svg>
622 - </div>
623 - <div class="merchant-quick-view-inner">
624 - <a href="#" class="merchant-quick-view-close-button" title="<?php echo esc_attr__( 'Close quick view modal', 'merchant' ); ?>">
625 - <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 320 512">
626 - <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"/>
627 - </svg>
628 - </a>
629 - <div class="merchant-quick-view-content"></div>
630 - </div>
631 - </div>
632 - <?php
525 + $template = ( 'side-panel' === $settings[ 'modal_layout' ] ) ? 'side-panel' : 'modal';
526 +
527 + merchant_get_template_part( self::MODULE_TEMPLATES, $template, array( 'settings' => $settings ) );
633 528 }
634 529
635 530 /**
636 531 * Quick view button.
@@ -754,8 +649,27 @@
754 649 }
755 650 }
756 651
757 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 + /**
758 672 * Prints the bulk discounts for the specified product.
759 673 *
760 674 * @param $product
761 675 *
@@ -797,10 +711,16 @@
797 711 if ( ! merchant_is_pro_active() || ! Merchant_Modules::is_module_active( Merchant_Buy_X_Get_Y::MODULE_ID ) ) {
798 712 return;
799 713 }
800 714
715 + $eligibility = Merchant_Pro_BXGY_Service_Provider::eligibility();
716 +
717 + if ( ! $eligibility ) {
718 + return;
719 + }
720 +
801 721 $product_id = $product->get_id();
802 - $offers = Merchant_Pro_Buy_X_Get_Y::availabe_offers( $product_id );
722 + $offers = $eligibility->get_eligible_for_product( $product_id );
803 723
804 724 if ( ! empty( $offers ) ) {
805 725 merchant_get_template_part(
806 726 Merchant_Buy_X_Get_Y::MODULE_TEMPLATES,
@@ -805,12 +725,13 @@
805 725 merchant_get_template_part(
806 726 Merchant_Buy_X_Get_Y::MODULE_TEMPLATES,
807 727 'single-product',
808 728 array(
809 - 'offers' => $offers,
810 - 'nonce' => wp_create_nonce( 'merchant_bogo_add_to_cart' ),
811 - 'settings' => Merchant_Admin_Options::get_all( Merchant_Buy_X_Get_Y::MODULE_ID ),
812 - '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,
813 734 )
814 735 );
815 736 }
816 737 }
@@ -826,23 +747,24 @@
826 747 if ( ! merchant_is_pro_active() || ! Merchant_Modules::is_module_active( Merchant_Frequently_Bought_Together::MODULE_ID ) ) {
827 748 return;
828 749 }
829 750
830 - $post_id = $product->get_id();
831 - $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 );
832 757
833 - if ( ! empty( $bundle_data ) ) {
834 - $bundles[ $post_id ] = Merchant_Pro_Frequently_Bought_Together::map_bundles( $bundle_data );
835 - }
836 -
837 758 if ( ! empty( $bundles ) ) {
838 759 merchant_get_template_part(
839 760 Merchant_Frequently_Bought_Together::MODULE_TEMPLATES_PATH,
840 - 'single-product',
761 + 'single-product-v3',
841 762 array(
842 - 'bundles' => $bundles,
843 - 'nonce' => wp_create_nonce( Merchant_Pro_Frequently_Bought_Together::AJAX_NONCE_ACTION ),
844 - '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,
845 767 )
846 768 );
847 769 }
848 770 }
@@ -895,8 +817,11 @@
895 817 $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'modal_width', 1000, '.merchant-quick-view-modal', '--mrc-qv-modal-width', 'px' );
896 818
897 819 // Modal Height.
898 820 $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'modal_height', 500, '.merchant-quick-view-modal', '--mrc-qv-modal-height', 'px' );
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' );
899 824
900 825 // Sale Price Color.
901 826 $css .= Merchant_Custom_CSS::get_variable_css( 'quick-view', 'sale-price-color', '#212121', '.merchant-quick-view-modal', '--mrc-qv-modal-sale-price-color' );
902 827