PluginProbe ʕ •ᴥ•ʔ
ShopPress – Shop Builder for Elementor and WooCommerce / trunk
ShopPress – Shop Builder for Elementor and WooCommerce vtrunk
shop-press / Modules / QuickView.php
shop-press / Modules Last commit date
VariationSwatches 1 week ago Wishlist 1 week ago AdminMessage.php 1 week ago AjaxSearch.php 1 week ago Backorder.php 1 week ago CatalogMode.php 1 year ago Compare.php 1 week ago DefaultTemplates.php 2 years ago FlashSalesCountdown.php 1 year ago MenuCart.php 4 months ago MobilePanel.php 1 week ago MultiStep.php 1 year ago Notifications.php 1 week ago QuickView.php 1 week ago RecentlyViewedProducts.php 1 year ago RenameLabel.php 4 months ago Shopify.php 1 year ago SingleAjaxAddToCart.php 1 week ago SizeChart.php 1 week ago StickyAddToCart.php 1 week ago
QuickView.php
524 lines
1 <?php
2 /**
3 * Quick View.
4 *
5 * @package ShopPress
6 */
7
8 namespace ShopPress\Modules;
9
10 defined( 'ABSPATH' ) || exit;
11
12 use Elementor\Plugin;
13 use ShopPress\Modules\VariationSwatches;
14
15 class QuickView {
16 /**
17 * Init hooks.
18 *
19 * @since 1.2.0
20 */
21 public static function init() {
22 add_action( 'wp_enqueue_scripts', array( __CLASS__, 'enqueue' ) );
23 add_action( 'wp_ajax_quick_view_ajax', array( __CLASS__, 'quick_view_ajax' ), 99 );
24 add_action( 'wp_ajax_nopriv_quick_view_ajax', array( __CLASS__, 'quick_view_ajax' ), 99 );
25 add_action( 'wp_footer', array( __CLASS__, 'footer_content' ) );
26 add_action( 'shoppress_quick_view_before_content', array( __CLASS__, 'essensial_scripts' ) );
27 add_action( 'shoppress_quick_view_before_content', array( __CLASS__, 'variation_swatches_template' ) );
28 add_filter( 'shoppress/elementor/widgets', array( __CLASS__, 'add_quick_view_widgets' ), 9 );
29
30 if ( self::is_quick_view_builder() ) {
31
32 add_action( 'shoppress_quick_view', array( __CLASS__, 'quick_view_content' ) );
33 } elseif ( self::is_static_quick_view() ) {
34
35 add_action( 'shoppress_quick_view_content', array( __CLASS__, 'title' ) );
36 add_action( 'shoppress_quick_view_content', array( __CLASS__, 'rating' ) );
37 add_action( 'shoppress_quick_view_content', array( __CLASS__, 'price' ) );
38 add_action( 'shoppress_quick_view_content', array( __CLASS__, 'add_to_cart' ) );
39 add_action( 'shoppress_quick_view_images', array( __CLASS__, 'images' ) );
40 // add_action( 'shoppress_quick_view_before_content', array( __CLASS__, 'variation_swatches_template' ) );
41 add_action( 'shoppress_quick_view_content', array( __CLASS__, 'social_share' ) );
42 }
43
44 $quick_view_location_archive = sp_get_module_settings( 'quick_view', 'location_products_loop' )['value'] ?? '';
45 if ( ! empty( $quick_view_location_archive ) ) {
46 add_action( $quick_view_location_archive, array( __CLASS__, 'static_quick_view_output' ) );
47 }
48 }
49
50 /**
51 * Adds the quick view widgets to the existing list of widgets.
52 *
53 * @param array $widgets The array of widgets.
54 *
55 * @since 1.2.0
56 *
57 * @return array The updated array of widgets.
58 */
59 public static function add_quick_view_widgets( $widgets ) {
60 $widgets['loop-quick-view'] = array(
61 'editor_type' => 'loop',
62 'class_name' => 'LoopBuilder\QuickView',
63 'is_pro' => false,
64 'path_key' => 'loop/quick-view',
65 );
66
67 return $widgets;
68 }
69
70 /**
71 * Check if quick view builder is enabled.
72 *
73 * @since 1.1.0
74 *
75 * @return bool
76 */
77 public static function is_quick_view_builder() {
78
79 if ( sp_get_template_settings( 'quick_view', 'status' ) && sp_get_template_settings( 'quick_view', 'page_builder' ) ) {
80 return true;
81 }
82
83 return false;
84 }
85
86 /**
87 * Check static compare.
88 *
89 * @since 1.7.
90 *
91 * @return bool
92 */
93 public static function is_static_quick_view() {
94
95 if ( sp_get_module_settings( 'quick_view', 'status' ) && ! self::is_quick_view_builder() ) {
96 return true;
97 }
98
99 return false;
100 }
101
102 /**
103 * Enqueue Scripts.
104 *
105 * @since 1.0.0
106 */
107 public static function enqueue() {
108
109 if ( ( is_page() || is_woocommerce() || is_tax( 'product_brand' ) ) && ! is_checkout() ) {
110
111 wp_enqueue_script( 'sp-quickview' );
112 wp_enqueue_style( 'sp-pr-general' );
113
114 if ( is_rtl() ) {
115 wp_enqueue_style( 'sp-pr-general-rtl' );
116 }
117
118 wp_enqueue_style( 'sp-quickview' );
119
120 if ( is_rtl() ) {
121 wp_enqueue_style( 'sp-quickview-rtl' );
122 }
123
124 wp_enqueue_script( 'flexslider' );
125
126 if ( current_theme_supports( 'wc-product-gallery-zoom' ) ) {
127 wp_enqueue_script( 'zoom' );
128 }
129
130 if ( current_theme_supports( 'wc-product-gallery-lightbox' ) ) {
131 wp_enqueue_script( 'photoswipe-ui-default' );
132 wp_enqueue_style( 'photoswipe-default-skin' );
133
134 if ( has_action( 'wp_footer', 'woocommerce_photoswipe' ) === false ) {
135 add_action( 'wp_footer', 'woocommerce_photoswipe', 15 );
136 }
137 }
138
139 wp_enqueue_script( 'wc-single-product' );
140
141 if ( self::is_quick_view_builder() ) {
142 wp_enqueue_style( 'elementor-frontend' );
143 }
144 }
145 }
146
147 /**
148 * Setup quick view data.
149 *
150 * @since 1.3.7
151 *
152 * @return \WC_Product
153 */
154 public static function setup_quick_view_data() {
155 check_ajax_referer( 'shoppress_nonce', 'nonce' );
156
157 global $shoppress_product_variation;
158 $shoppress_product_variation = false;
159
160 if ( ! isset( $_POST['product_id'] ) ) {
161 wp_die();
162 }
163 $product_id = absint( sanitize_text_field( wp_unslash( $_POST['product_id'] ) ) );
164 $_product = wc_get_product( $product_id );
165 $parent_id = $_product->get_parent_id();
166 if ( $parent_id ) {
167 $shoppress_product_variation = $_product;
168 $_product = wc_get_product( $parent_id );
169 }
170
171 global $post;
172
173 $post = get_post( $_product->get_id() );
174 $GLOBALS['product'] = $_product;
175
176 setup_postdata( $post );
177
178 return $_product;
179 }
180
181 /**
182 * Returns the content of the page that has been selected as the quick view.
183 *
184 * @since 1.1.0
185 */
186 public static function quick_view_content() {
187
188 if ( self::is_quick_view_builder() ) {
189
190 $product = self::setup_quick_view_data();
191
192 do_action( 'shoppress_quick_view_before_content', $product );
193 $quick_view_page = sp_get_template_settings( 'quick_view', 'page_builder' );
194 ?>
195 <div id="product-<?php the_ID(); ?>" <?php wc_product_class( 'sp-qv-wrap', $product ); ?>>
196 <?php
197 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
198 echo sp_get_builder_content( $quick_view_page );
199 ?>
200 </div>
201 <?php
202 do_action( 'shoppress_quick_view_after_content', $product );
203 }
204 }
205
206 /**
207 * Footer content.
208 *
209 * @since 1.0.0
210 */
211 public static function footer_content() {
212
213 if ( is_woocommerce() || is_page() ) {
214 ?>
215 <div id="sp-quick-view-overlay" style="display: none;">
216 <div id="sp-quick-view-content" class="woocommerce">
217 <div id="sp-close-quick-view"> <svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" viewBox="0 0 10 10" > <path d="M9.79.21a.717.717,0,0,1,0,1.014L5.956,5.057,9.674,8.776A.717.717,0,0,1,8.66,9.79L4.942,6.072l-3.6,3.6A.717.717,0,0,1,.326,8.66l3.6-3.6L.21,1.34A.717.717,0,0,1,1.224.326L4.942,4.043,8.776.21A.717.717,0,0,1,9.79.21Z" fill="#7f8da0" /> </svg> </div>
218 <div id="sp-quick-view-html"></div>
219 </div>
220 </div>
221 <?php
222 }
223 }
224
225 /**
226 * Quick View Ajax.
227 *
228 * @since 1.1.0
229 */
230 public static function quick_view_ajax() {
231 check_ajax_referer( 'shoppress_nonce', 'nonce' );
232
233 $product = self::setup_quick_view_data();
234
235 if ( ! is_a( $product, '\WC_Product' ) ) {
236 wp_die();
237 }
238
239 $content = '';
240 if ( self::is_quick_view_builder() ) {
241
242 ob_start();
243 do_action( 'shoppress_quick_view' );
244 $content = ob_get_clean();
245 } elseif ( self::is_static_quick_view() ) {
246
247 $content = self::static_quick_view_content_output();
248 }
249
250 wp_send_json(
251 array(
252 'content' => $content,
253 )
254 );
255 }
256
257 /**
258 * Load essential scripts.
259 *
260 * @since 1.2.0
261 */
262 public static function essensial_scripts() {
263 // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript -- Quick view modal loads scripts inline for AJAX context.
264 echo '<script type="text/javascript" src="' . esc_url( plugins_url( 'assets/js/frontend/add-to-cart-variation.js', WC_PLUGIN_FILE ) ) . '"></script>';
265 // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript -- Quick view modal loads scripts inline for AJAX context.
266 echo '<script type="text/javascript" src="' . esc_url( plugins_url( 'assets/js/frontend/single-product.js', WC_PLUGIN_FILE ) ) . '"></script>';
267 // phpcs:ignore WordPress.WP.EnqueuedResources.NonEnqueuedScript -- Quick view modal loads scripts inline for AJAX context.
268 echo '<script type="text/javascript" src="' . esc_url( SHOPPRESS_URL . 'public/modules/variation-swatches/front/js/sp-variation-swatches.js' ) . '"></script>';
269
270 \WC_Frontend_Scripts::load_scripts();
271
272 wp_print_styles( 'woocommerce-general' );
273 wp_print_styles( 'sp-variation-swatches' );
274
275 if ( is_rtl() ) {
276 wp_print_styles( 'sp-variation-swatches-rtl' );
277 }
278
279 wp_print_styles( 'sp-single' );
280
281 if ( is_rtl() ) {
282 wp_print_styles( 'sp-single-rtl' );
283 }
284 }
285
286 /**
287 * Product title.
288 *
289 * @since 1.0.0
290 */
291 public static function title() {
292 ?>
293 <h3 class="sp-qv-title"><?php echo esc_html( get_the_title() ); ?></h3>
294 <?php
295 }
296
297 /**
298 * Product price.
299 *
300 * @since 1.0.0
301 */
302 public static function price() {
303 global $product;
304 ?>
305 <div class="sp-price-wrapper">
306 <p class="<?php echo esc_attr( apply_filters( 'woocommerce_product_price_class', 'price' ) ); ?>">
307 <?php echo wp_kses_post( $product->get_price_html() ); ?>
308 </p>
309 </div>
310 <?php
311 }
312
313 /**
314 * Product rating.
315 *
316 * @since 1.0.0
317 */
318 public static function rating() {
319 $args = array(
320 'show_review_counter' => 'yes',
321 );
322
323 sp_load_builder_template( 'single-product/product-rating', $args );
324 }
325
326 /**
327 * Checks if the current request is an AJAX request for the quick view feature.
328 *
329 * @since 1.2.0
330 *
331 * @return bool
332 */
333 public static function is_quick_view_ajax() {
334 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Request type detection only; nonce verified in quick_view_ajax handler.
335 return is_ajax() && isset( $_POST['action'] ) && 'quick_view_ajax' === sanitize_text_field( wp_unslash( $_POST['action'] ) );
336 }
337
338 /**
339 * Product add to cart.
340 *
341 * @since 1.0.0
342 */
343 public static function add_to_cart() {
344 global $product;
345
346 ?>
347 <div class="sp-add-to-cart-wrapper product-<?php echo esc_attr( $product->get_type() ); ?>">
348 <?php
349 switch ( $product->get_type() ) {
350 case 'simple':
351 woocommerce_simple_add_to_cart();
352 break;
353
354 case 'grouped':
355 woocommerce_grouped_add_to_cart();
356 break;
357
358 case 'variable':
359 woocommerce_variable_add_to_cart();
360 break;
361
362 case 'external':
363 woocommerce_external_add_to_cart();
364 break;
365 }
366 ?>
367 </div>
368 <?php
369 }
370
371 /**
372 * Product images.
373 *
374 * @since 1.0.0
375 */
376 public static function images() {
377
378 if ( ! function_exists( 'wc_get_gallery_image_html' ) ) {
379 return;
380 }
381
382 global $post, $product;
383
384 $columns = 4;
385
386 $post_thumbnail_id = $product->get_image_id();
387
388 $wrapper_classes = apply_filters(
389 'woocommerce_single_product_image_gallery_classes',
390 array(
391 'woocommerce-product-gallery',
392 'woocommerce-product-gallery--' . ( $post_thumbnail_id ? 'with-images' : 'without-images' ),
393 'woocommerce-product-gallery--columns-' . absint( $columns ),
394 'images',
395 )
396 );
397 ?>
398 <div class="sp-images">
399 <div class="<?php echo esc_attr( implode( ' ', array_map( 'sanitize_html_class', $wrapper_classes ) ) ); ?>" data-columns="<?php echo esc_attr( $columns ); ?>">
400 <figure class="woocommerce-product-gallery__wrapper">
401 <?php
402 if ( $post_thumbnail_id ) {
403 $html = wc_get_gallery_image_html( $post_thumbnail_id, true );
404 } else {
405 $html = '<div class="woocommerce-product-gallery__image--placeholder">';
406 $html .= sprintf( '<img src="%s" alt="%s" class="wp-post-image" />', esc_url( wc_placeholder_img_src( 'woocommerce_single' ) ), esc_html__( 'Awaiting product image', 'shop-press' ) );
407 $html .= '</div>';
408 }
409
410 echo wp_kses_post( apply_filters( 'woocommerce_single_product_image_thumbnail_html', $html, $post_thumbnail_id ) );
411
412 do_action( 'woocommerce_product_thumbnails' );
413
414 ?>
415 </figure>
416 </div>
417 </div>
418 <?php
419 }
420
421 /**
422 * Product thumbnails.
423 *
424 * @since 1.2.0
425 */
426 public static function thumbnails() {
427 // echo wp_kses_post( woocommerce_get_product_thumbnail( 'woocommerce_full_size' ) );
428 }
429
430 /**
431 * Icon.
432 *
433 * @since 1.0.0
434 */
435 public static function get_icon() {
436 return '<svg xmlns="http://www.w3.org/2000/svg" width="18" height="14.25" viewBox="0 0 18 14.25"> <defs> <clipPath id="sp-quick-view-icon"> <rect width="18" height="14.25" transform="translate(615.623 4145)" fill="#959ca7"/> </clipPath> </defs> <g transform="translate(-615.623 -4145)" clip-path="url(#sp-quick-view-icon)"> <path d="M9.095,3a9,9,0,0,1,8.716,6.75,9,9,0,0,1-17.433,0A9,9,0,0,1,9.095,3Zm0,12A7.5,7.5,0,0,1,1.937,9.75a7.5,7.5,0,0,1,14.314,0A7.5,7.5,0,0,1,9.095,15Z" transform="translate(615.528 4142.75)" fill="#959ca7" fill-rule="evenodd"/> <path d="M14,11a3,3,0,1,1-3-3A3,3,0,0,1,14,11Zm-1.5,0A1.5,1.5,0,1,1,11,9.5,1.5,1.5,0,0,1,12.5,11Z" transform="translate(613.622 4141.5)" fill="#959ca7" fill-rule="evenodd"/> </g> </svg> ';
437 }
438
439 /**
440 * Quick view output.
441 *
442 * @since 1.0.0
443 */
444 public static function static_quick_view_output() {
445 global $shoppress_cross_sell_popup;
446 // Do not display the variations in cross-sell popup
447 if ( $shoppress_cross_sell_popup ) {
448 return;
449 }
450
451 $product_id = get_the_ID();
452
453 ?>
454 <div class="sp-quick-view" data-product_id="<?php echo esc_attr( $product_id ); ?>">
455 <i class="sp-quick-view-icon">
456 <?php echo wp_kses( self::get_icon(), sp_allowd_svg_tags() ); ?>
457 </i>
458 <span class="sp-quick-view-label"><?php esc_html_e( 'Quick View', 'shop-press' ); ?></span>
459 </div>
460 <?php
461 }
462
463 /**
464 * Variation Swatches template.
465 *
466 * @since 1.2.0
467 */
468 public static function variation_swatches_template() {
469
470 // If variation is not activated return do not run the function anymore
471 if ( ! sp_is_module_active( 'variation_swatches' ) ) {
472 return false;
473 }
474
475 // Create instance of VariationSwatches\Frontend
476 $VariationSwatches = new VariationSwatches\Frontend();
477
478 // Run necessary hooks for filter the WC variation swatches
479 $VariationSwatches->public_hook_definition();
480 }
481
482 /**
483 * Display social share links.
484 *
485 * @since 1.3.7
486 *
487 * @return void
488 */
489 public static function social_share() {
490 $is_active_share = sp_get_module_settings( 'quick_view', 'social_share', false );
491 if ( ! $is_active_share ) {
492 return;
493 }
494
495 $_links = sp_get_module_settings( 'quick_view', 'social_media' );
496 $_links = array_column( $_links, 'value' );
497
498 $args = array(
499 'type' => 'icon-label',
500 'label' => __( 'Share', 'shop-press' ),
501 'links' => $_links,
502 );
503
504 include sp_get_template_path( 'general/product-sharing' );
505 }
506
507 /**
508 * Quick view content output.
509 *
510 * @since 1.0.0
511 */
512 public static function static_quick_view_content_output() {
513 ob_start();
514
515 load_template( sp_get_template_path( 'quick-view/quick-view-content' ) );
516
517 $content = ob_get_contents();
518
519 ob_end_clean();
520
521 return $content;
522 }
523 }
524