PluginProbe
ShopBuilder – WooCommerce Builder For Elementor / 3.4.0
ShopBuilder – WooCommerce Builder For Elementor v3.4.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
← All changes | app/Modules/VariationGallery/GalleryFrontEnd.php +3 -261 3.4.23.4.0 View file →
@@ -28,24 +28,10 @@
28 28 */
29 29 private function __construct() {
30 30 add_filter( 'woocommerce_locate_template', [ $this, 'override_templates' ], 10, 2 );
31 31 add_action( 'wp_footer', [ $this, 'slider_and_thumbnail_template_js' ] );
32 -
33 - // Side (left/right) thumbnail layouts are free. Pro re-filters both of these at
34 - // its own priority and wins where the two overlap, so pro behaviour is unchanged.
35 - add_filter( 'rtsb/vg/slider/options', [ $this, 'side_thumbnail_slider_options' ] );
36 - add_filter( 'rtsb/vg/thumbnails/slider/options', [ $this, 'side_thumbnails_slider_options' ], 10, 2 );
37 32 add_filter( 'woocommerce_available_variation', [ $this, 'available_variation_gallery' ], 90, 3 );
38 - add_filter( 'woocommerce_product_variation_get_gallery_image_ids', [ $this, 'suppress_native_variation_gallery' ], 20, 2 );
39 33
40 - // Track the variation form so its embedded "default gallery" snapshot can be
41 - // skipped. `wc_get_template` (not `woocommerce_locate_template`) is what the
42 - // stub swaps on, because WooCommerce caches the located path and skips the
43 - // locate filter on repeat renders within the same request.
44 - add_action( 'woocommerce_before_template_part', [ $this, 'mark_variation_form_open' ] );
45 - add_action( 'woocommerce_after_template_part', [ $this, 'mark_variation_form_closed' ] );
46 - add_filter( 'wc_get_template', [ $this, 'skip_native_gallery_snapshot' ], 60, 2 );
47 -
48 34 add_action( 'wp_ajax_rtsb_vg_get_default_gallery_images', [ $this, 'get_default_gallery_images' ] );
49 35 add_action( 'wp_ajax_nopriv_rtsb_vg_get_default_gallery_images', [ $this, 'get_default_gallery_images' ] );
50 36
51 37 // On-demand single-variation gallery. Nonce-less / read-only by design,
@@ -78,23 +64,8 @@
78 64 if ( apply_filters( 'rtsb/vg/disable_wc_variation_image', true, $available_variation, $variation ) ) {
79 65 unset( $available_variation['image'], $available_variation['image_id'] );
80 66 }
81 67
82 - /*
83 - * WooCommerce 11.1+ also ships gallery markup in `gallery_images_html` and
84 - * swaps it in from `add-to-cart-variation.js`, replacing the whole
85 - * `.woocommerce-product-gallery` element. Our gallery owns that DOM, so the
86 - * payload is dropped to keep core's swap from competing with ours — and to
87 - * keep a duplicate copy of the gallery out of `data-product_variations`.
88 - *
89 - * suppress_native_variation_gallery() normally stops this being built at
90 - * all; blanking it here is the belt-and-braces for any request where the
91 - * gallery ids were re-added by a third party after that filter ran.
92 - */
93 - if ( GalleryFns::use_native_gallery() && isset( $available_variation['gallery_images_html'] ) ) {
94 - $available_variation['gallery_images_html'] = '';
95 - }
96 -
97 68 // Inline the gallery for small products so variation swaps are instant with no
98 69 // per-click AJAX (the frontend renders variation_gallery_images directly). For
99 70 // large products we omit it and fall back to the lazy AJAX path
100 71 // (get_variation_gallery()) to keep the page lean. WooCommerce itself only
@@ -123,216 +94,8 @@
123 94 return apply_filters( 'rtsb/vg/available/variation/gallery', $available_variation, $variation, $variation_id );
124 95 }
125 96
126 97 /**
127 - * Turn the main slider into a thumbnail-linked Swiper for side layouts.
128 - *
129 - * The bottom layout is deliberately left alone: its thumbnails are plain stacked
130 - * items (`thumbsSelectorNoSlider`), and switching it to a Swiper would change how
131 - * every existing free site renders. Only left/right — which need a vertical,
132 - * linked thumbnail strip — are adjusted here.
133 - *
134 - * @param array $slider_options Main slider options.
135 - *
136 - * @return array
137 - */
138 - public function side_thumbnail_slider_options( $slider_options ) {
139 - if ( ! $this->is_side_thumbnail_layout( GalleryFns::get_gallery_style() ) ) {
140 - return $slider_options;
141 - }
142 -
143 - // Side layouts always track the active image's height: the two columns sit
144 - // next to each other, so sizing to the tallest slide would leave a blank gap
145 - // under a short image.
146 - $slider_options['autoHeight'] = true;
147 - $slider_options['observer'] = true;
148 - $slider_options['observeParents'] = true;
149 - $slider_options['thumbsSelector'] = '.rtsb-vg-thumb-slider';
150 -
151 - unset( $slider_options['thumbsSelectorNoSlider'] );
152 -
153 - return $slider_options;
154 - }
155 -
156 - /**
157 - * Supply the vertical thumbnail Swiper options for side layouts.
158 - *
159 - * @param array $options Thumbnail slider options.
160 - * @param array $args Render args (thumbnailsPosition, randDom).
161 - *
162 - * @return array
163 - */
164 - public function side_thumbnails_slider_options( $options, $args ) {
165 - $position = $args['thumbnailsPosition'] ?? 'bottom';
166 -
167 - if ( ! $this->is_side_thumbnail_layout( $position ) ) {
168 - return $options;
169 - }
170 -
171 - $col = GalleryFns::get_options( 'thumbnails_columns' );
172 - $gap = GalleryFns::get_options( 'thumbnails_gap' );
173 -
174 - return [
175 - 'slidesPerView' => absint( $col ?: 4 ),
176 - 'spaceBetween' => ( null === $gap || '' === $gap ) ? 10 : absint( $gap ),
177 - 'direction' => 'vertical',
178 - 'speed' => 500,
179 - 'loop' => false,
180 - 'navigation' => [
181 - 'nextEl' => '.swiper-gallery-next.rtsb-random-id-' . esc_attr( $args['randDom'] ?? '' ),
182 - 'prevEl' => '.swiper-gallery-prev.rtsb-random-id-' . esc_attr( $args['randDom'] ?? '' ),
183 - ],
184 - ] + $options;
185 - }
186 -
187 - /**
188 - * Whether a gallery style places the thumbnails beside the main image.
189 - *
190 - * @param string $style Gallery style / thumbnail position.
191 - *
192 - * @return bool
193 - */
194 - private function is_side_thumbnail_layout( $style ) {
195 - return in_array( $style, [ 'left', 'right' ], true );
196 - }
197 -
198 - /**
199 - * Whether WooCommerce is currently rendering the variable add-to-cart template.
200 - *
201 - * @var bool
202 - */
203 - private $rendering_variation_form = false;
204 -
205 - /**
206 - * Whether this module's gallery template replaced WooCommerce's for this request.
207 - *
208 - * Used to decide when it is safe to stop WooCommerce building its own variation
209 - * gallery output: only once our template is demonstrably the one rendering the
210 - * product images. Block themes and the WooCommerce Product Gallery block never go
211 - * through `single-product/product-image.php`, so they must keep reading the native
212 - * gallery untouched even though `is_product()` is true there.
213 - *
214 - * @var bool
215 - */
216 - private $gallery_template_rendered = false;
217 -
218 - /**
219 - * Note that the variable add-to-cart template has started rendering.
220 - *
221 - * @param string $template_name Template being rendered.
222 - *
223 - * @return void
224 - */
225 - public function mark_variation_form_open( $template_name ) {
226 - if ( 'single-product/add-to-cart/variable.php' === $template_name ) {
227 - $this->rendering_variation_form = true;
228 - }
229 - }
230 -
231 - /**
232 - * Note that the variable add-to-cart template has finished rendering.
233 - *
234 - * @param string $template_name Template that finished rendering.
235 - *
236 - * @return void
237 - */
238 - public function mark_variation_form_closed( $template_name ) {
239 - if ( 'single-product/add-to-cart/variable.php' === $template_name ) {
240 - $this->rendering_variation_form = false;
241 - }
242 - }
243 -
244 - /**
245 - * Skip the gallery snapshot WooCommerce embeds inside the variation form.
246 - *
247 - * `single-product/add-to-cart/variable.php` renders the whole product gallery a
248 - * second time into a hidden `<template>`, so core's variation script can restore it
249 - * after swapping in per-variation markup. That swap never happens here — the
250 - * payload driving it is dropped in available_variation_gallery() — so the snapshot
251 - * is dead weight: it would duplicate the entire slider on every variable product
252 - * page and fire the gallery's render hooks a second time.
253 - *
254 - * Scoped to renders that happen *inside* the variation form, so a genuine second
255 - * gallery elsewhere on the page is untouched.
256 - *
257 - * @param string $template Resolved template path.
258 - * @param string $template_name Template name being loaded.
259 - *
260 - * @return string
261 - */
262 - public function skip_native_gallery_snapshot( $template, $template_name ) {
263 - if ( 'single-product/product-image.php' !== $template_name ) {
264 - return $template;
265 - }
266 -
267 - // Re-assert ownership here as well as in override_templates(): WooCommerce
268 - // caches the located path, so on a store with a persistent object cache the
269 - // locate filter can be skipped entirely while this one always runs. The
270 - // snapshot render is excluded, otherwise it would claim ownership on behalf of
271 - // a gallery that has not actually been rendered.
272 - if ( ! $this->rendering_variation_form && false !== strpos( $template, 'variation-gallery' ) ) {
273 - $this->gallery_template_rendered = true;
274 - }
275 -
276 - if ( ! $this->rendering_variation_form ) {
277 - return $template;
278 - }
279 -
280 - if ( ! GalleryFns::use_native_gallery() || ! $this->gallery_template_rendered || ! $this->is_single_product_context() ) {
281 - return $template;
282 - }
283 -
284 - if ( ! apply_filters( 'rtsb/vg/skip/native/gallery/snapshot', true ) ) {
285 - return $template;
286 - }
287 -
288 - $stub = Fns::locate_template( 'variation-gallery/vg-noop' );
289 -
290 - return file_exists( $stub ) ? $stub : $template;
291 - }
292 -
293 - /**
294 - * Stop WooCommerce building its own variation gallery markup on the frontend.
295 - *
296 - * `WC_Product_Variable::get_available_variation()` renders
297 - * `single-product/product-image.php` once per variation whenever the native gallery
298 - * holds images — and on a single product page that template is ours, so after
299 - * migration every variation would re-render the full slider into
300 - * `data-product_variations`. Returning an empty list skips that render entirely;
301 - * the gallery data our script consumes is supplied separately through
302 - * `variation_gallery_images` and the on-demand AJAX endpoint.
303 - *
304 - * Only the `view` context reaches this filter, so
305 - * `GalleryFns::get_native_variation_gallery_ids()` (which reads in `edit` context)
306 - * and every admin/REST/CSV reader still see the stored value.
307 - *
308 - * @param array $gallery_image_ids Native gallery image IDs.
309 - * @param \WC_Product $variation Variation object.
310 - *
311 - * @return array
312 - */
313 - public function suppress_native_variation_gallery( $gallery_image_ids, $variation ) {
314 - if ( is_admin() || ( defined( 'REST_REQUEST' ) && REST_REQUEST ) ) {
315 - return $gallery_image_ids;
316 - }
317 -
318 - // `gallery_template_rendered` is the load-bearing condition, not just a
319 - // shortcut: block themes and the WooCommerce Product Gallery block read this
320 - // same prop on a single product page (where is_single_product_context() is
321 - // true) but never render our template, so suppressing there would empty their
322 - // galleries instead of ours.
323 - if ( ! GalleryFns::use_native_gallery() || ! $this->gallery_template_rendered || ! $this->is_single_product_context() ) {
324 - return $gallery_image_ids;
325 - }
326 -
327 - if ( ! apply_filters( 'rtsb/vg/suppress/native/variation/gallery', true, $variation ) ) {
328 - return $gallery_image_ids;
329 - }
330 -
331 - return [];
332 - }
333 -
334 - /**
335 98 * Whether the current request is rendering a single product page (where this
336 99 * module owns the gallery), as opposed to an archive/shop context.
337 100 *
338 101 * On page render `is_product()` / BuilderFns::is_product() are reliable. During
@@ -361,27 +124,10 @@
361 124 if ( wp_doing_ajax() ) {
362 125 $referer = wp_get_referer();
363 126 if ( $referer ) {
364 127 $referer_id = url_to_postid( $referer );
365 - if ( $referer_id ) {
366 - $referer_type = get_post_type( $referer_id );
367 -
368 - if ( 'product' === $referer_type ) {
369 - $is_single = true;
370 - } elseif ( BuilderFns::$post_type_tb === $referer_type && 'product' === BuilderFns::builder_type( $referer_id ) ) {
371 - /*
372 - * A ShopBuilder single-product template rendered on its own URL
373 - * (the template-builder preview). The referring post is a
374 - * `rtsb_builder` template rather than a product, so the check
375 - * above misses it — but that page renders this module's gallery
376 - * exactly like a product page does.
377 - *
378 - * Without this, WooCommerce's `get_variation` AJAX keeps its own
379 - * `gallery_images_html`, and `wc_variations_image_update()`
380 - * replaceWith()s our entire gallery on every variation change.
381 - */
382 - $is_single = true;
383 - }
128 + if ( $referer_id && 'product' === get_post_type( $referer_id ) ) {
129 + $is_single = true;
384 130 }
385 131 }
386 132 }
387 133
@@ -482,17 +228,13 @@
482 228 */
483 229 public function override_templates( $template, $template_name ) {
484 230 // List of templates you want to override.
485 231 if ( 'single-product/product-image.php' === $template_name ) {
486 - $galleryStyle = GalleryFns::get_gallery_style();
232 + $galleryStyle = GalleryFns::get_options( 'gallery_style' );
487 233 $galleryStyle = apply_filters( 'rtsb/vg/thumbnails/position', $galleryStyle );
488 234 $temp = rtsb()->has_pro() && 'grid' === $galleryStyle ? 'variation-gallery/vg-grid-view' : 'variation-gallery/product-image';
489 235 $custom_template = Fns::locate_template( $temp );
490 236 if ( file_exists( $custom_template ) ) {
491 - // Record that our gallery — not WooCommerce's — is what this request
492 - // renders, so the native-output suppression below can safely engage.
493 - $this->gallery_template_rendered = true;
494 -
495 237 return $custom_template;
496 238 }
497 239 }
498 240 return $template;