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

GalleryFrontEnd.php in ShopBuilder – WooCommerce Builder For Elementor 3.3.0, at app/Modules/VariationGallery/GalleryFrontEnd.php

187 lines 6.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Main FilterHooks class.
4 *
5 * @package RadiusTheme\SB
6 */
7
8 namespace RadiusTheme\SB\Modules\VariationGallery;
9
10 use RadiusTheme\SB\Helpers\BuilderFns;
11 use RadiusTheme\SB\Helpers\Fns;
12 use RadiusTheme\SB\Traits\SingletonTrait;
13
14 defined( 'ABSPATH' ) || exit();
15
16 /**
17 * Main FilterHooks class.
18 */
19 class GalleryFrontEnd {
20
21 /**
22 * Singleton Trait.
23 */
24 use SingletonTrait;
25
26 /**
27 * Module Class Constructor.
28 */
29 private function __construct() {
30 add_filter( 'woocommerce_locate_template', [ $this, 'override_templates' ], 10, 2 );
31 add_action( 'wp_footer', [ $this, 'slider_and_thumbnail_template_js' ] );
32 add_filter( 'woocommerce_available_variation', [ $this, 'available_variation_gallery' ], 90, 3 );
33
34 add_action( 'wp_ajax_rtsb_vg_get_default_gallery_images', [ $this, 'get_default_gallery_images' ] );
35 add_action( 'wp_ajax_nopriv_rtsb_vg_get_default_gallery_images', [ $this, 'get_default_gallery_images' ] );
36
37 // On-demand single-variation gallery. Nonce-less / read-only by design,
38 // mirroring WooCommerce core's own `woocommerce_get_variation` AJAX: a
39 // required nonce breaks on full-page-cached pages because the embedded
40 // nonce goes stale, and the payload is public, read-only product images.
41 add_action( 'wp_ajax_rtsb_get_variation_gallery', [ $this, 'get_variation_gallery' ] );
42 add_action( 'wp_ajax_nopriv_rtsb_get_variation_gallery', [ $this, 'get_variation_gallery' ] );
43 }
44 /**
45 * @param array $available_variation Available variation.
46 * @param object $variationProductObject object.
47 * @param object $variation variation.
48 *
49 * @return array
50 */
51 public function available_variation_gallery( $available_variation, $variationProductObject, $variation ) {
52 $variation_id = absint( $variation->get_id() );
53
54 // On single product pages galleries are fetched on-demand over AJAX (see
55 // get_variation_gallery()), so we intentionally do NOT embed per-variation image
56 // props in the variation JSON — that keeps the page lean and ensures each
57 // variation's gallery is fetched only when it is selected. WooCommerce already
58 // includes `variation_id`, which is all the frontend needs to request it.
59 //
60 // In other contexts (e.g. the archive/shop variation image swap) the inline
61 // data is still consumed, so expose an already-cached gallery if one exists.
62 // This is a cheap get_transient() — no prop building.
63 if ( ! is_product() && ! BuilderFns::is_product() ) {
64 $transient_name = GalleryFns::get_transient_name( $variation_id, 'variation-images' );
65 $images = $transient_name ? get_transient( $transient_name ) : false;
66 if ( ! empty( $images ) && is_array( $images ) ) {
67 $available_variation['variation_gallery_images'] = array_values( $images );
68 }
69 }
70
71 return apply_filters( 'rtsb/vg/available/variation/gallery', $available_variation, $variation, $variation_id );
72 }
73 /**
74 * @return void
75 */
76 public function get_default_gallery_images() {
77 if ( ! wp_verify_nonce( Fns::get_nonce(), rtsb()->nonceText ) ) {
78 wp_send_json_error( esc_html__( 'Something Went Wrong', 'shopbuilder' ) );
79 }
80 $product_id = isset( $_POST['product_id'] ) ? absint( $_POST['product_id'] ) : 0;
81
82 if ( ! $product_id ) {
83 wp_send_json_error( esc_html__( 'Invalid product ID.', 'shopbuilder' ) );
84 }
85
86 $product = wc_get_product( $product_id );
87
88 if ( ! $product ) {
89 wp_send_json_error( esc_html__( 'Product not found.', 'shopbuilder' ) );
90 }
91
92 if ( ! $this->can_user_view_product( $product ) ) {
93 wp_send_json_error( esc_html__( 'You do not have permission to view this product.', 'shopbuilder' ) );
94 }
95
96 $product_id = isset( $_POST['product_id'] ) ? absint( $_POST['product_id'] ) : 0;
97 $images = GalleryFns::get_gallery_images_and_props( $product_id );
98 wp_send_json_success( $images );
99 }
100
101 /**
102 * AJAX: Return the gallery image props for a single selected variation.
103 *
104 * Read-only / nonce-less by design, mirroring WooCommerce core's own
105 * `woocommerce_get_variation` endpoint. A required nonce would break on
106 * full-page-cached pages (stale embedded nonce); the response is public,
107 * read-only product image data, so there is no CSRF concern.
108 *
109 * @return void
110 */
111 public function get_variation_gallery() {
112 // phpcs:ignore WordPress.Security.NonceVerification.Missing
113 $variation_id = isset( $_POST['variation_id'] ) ? absint( wp_unslash( $_POST['variation_id'] ) ) : 0;
114 // phpcs:ignore WordPress.Security.NonceVerification.Missing
115 $product_id = isset( $_POST['product_id'] ) ? absint( wp_unslash( $_POST['product_id'] ) ) : 0;
116
117 if ( ! $variation_id ) {
118 wp_send_json_error( esc_html__( 'Invalid variation ID.', 'shopbuilder' ) );
119 }
120
121 $variation = wc_get_product( $variation_id );
122
123 if ( ! $variation || 'variation' !== $variation->get_type() ) {
124 wp_send_json_error( esc_html__( 'Variation not found.', 'shopbuilder' ) );
125 }
126
127 if ( ! $product_id ) {
128 $product_id = absint( $variation->get_parent_id() );
129 }
130
131 $product = $product_id ? wc_get_product( $product_id ) : false;
132
133 if ( ! $product || ! $this->can_user_view_product( $product ) ) {
134 wp_send_json_error( esc_html__( 'You do not have permission to view this product.', 'shopbuilder' ) );
135 }
136
137 $images = GalleryFns::get_variation_gallery( $product_id, $variation_id );
138 wp_send_json_success( $images );
139 }
140
141 /**
142 * Determines if the current user has permission to view a product.
143 *
144 * Checks product status and visibility settings against user capabilities.
145 *
146 * @param \WC_Product $product The product to check access for.
147 * @return bool True if user can view the product, false otherwise.
148 */
149 private function can_user_view_product( $product ) {
150 $product_id = $product->get_id();
151 $status = get_post_status( $product->get_id() );
152 $visibility = $product->get_catalog_visibility();
153
154 if ( 'publish' === $status && 'visible' === $visibility ) {
155 return true;
156 }
157
158 return current_user_can( 'edit_post', $product_id );
159 }
160 /**
161 * @param string $template template.
162 * @param string $template_name template name.
163 * @return mixed|null
164 */
165 public function override_templates( $template, $template_name ) {
166 // List of templates you want to override.
167 if ( 'single-product/product-image.php' === $template_name ) {
168 $galleryStyle = GalleryFns::get_options( 'gallery_style' );
169 $galleryStyle = apply_filters( 'rtsb/vg/thumbnails/position', $galleryStyle );
170 $temp = rtsb()->has_pro() && 'grid' === $galleryStyle ? 'variation-gallery/vg-grid-view' : 'variation-gallery/product-image';
171 $custom_template = Fns::locate_template( $temp );
172 if ( file_exists( $custom_template ) ) {
173 return $custom_template;
174 }
175 }
176 return $template;
177 }
178 /**
179 * @return void
180 */
181 public function slider_and_thumbnail_template_js() {
182 wp_enqueue_script( 'underscore' );
183 Fns::load_template( 'variation-gallery/vg-slider-template', [] );
184 Fns::load_template( 'variation-gallery/vg-thumbnail-template', [] );
185 }
186 }
187