HEX
Server: Apache
System: Linux webd006.cluster128.gra.hosting.ovh.net 6.18.42-ovh-vps-grsec-zfs+ #1 SMP PREEMPT_DYNAMIC Wed Aug 5 15:59:48 CEST 2026 x86_64
User: zwafgyp (177615)
PHP: 7.4.33
Disabled: _dyuweyrj4,_dyuweyrj4r,dl
Upload Files
File: /home/zwafgyp/lacalita/wp-content/plugins/rey-core/inc/woocommerce/pdp-components/gallery.php
<?php
namespace ReyCore\WooCommerce\PdpComponents;

if (!defined('ABSPATH')) exit; // Exit if accessed directly

class Gallery extends Component {

	protected $galleries = [];

	private $__added_lazy_loading = false;

	public function __construct(){
		add_action( 'init', [$this, 'register_galleries']);
		add_filter( 'woocommerce_get_image_size_gallery_thumbnail', [$this, 'disable_thumbs_cropping']);
		add_action( 'wp_head', [$this, 'preload_main_image']);
		add_action( 'reycore/frontend/wp_head', [ $this, 'body_classes'], 30 );
		add_filter( 'reycore/quickview/ajax_response', [$this, 'include_pswp_in_quickview'], 10, 2 );
		add_filter( 'reycore/delay_js/exclusions', [$this, 'append_delay_js_exclusions']);
	}

	/**
	 * Register Gallery types
	 *
	 * @return void
	 */
	public function register_galleries(){

		$default_galleries = [
			'PdpComponents/GalleryCascadeGrid',
			'PdpComponents/GalleryCascadeScattered',
			'PdpComponents/GalleryCascade',
			'PdpComponents/GalleryGrid',
			'PdpComponents/GalleryGridPattern',
			'PdpComponents/GalleryHorizontal',
			'PdpComponents/GalleryVertical',
		];

		foreach ($default_galleries as $item) {

			$class_name = \ReyCore\Helper::fix_class_name($item, 'WooCommerce');
			$gallery = new $class_name();

			if( $gallery_id = $gallery->get_id() ){
				$this->galleries[ $gallery_id ] = $gallery;
			}

		}

		do_action('reycore/woocommerce/pdp/gallery/init', $this);

	}

	/**
	 * Initialize Gallery Component
	 *
	 * @return void
	 */
	public function init(){

		add_filter( 'woocommerce_single_product_image_gallery_classes', [$this, 'gallery_classes']);
		add_filter( 'woocommerce_gallery_image_html_attachment_image_params', [$this, 'filter_image_attributes'], 20, 4);
		add_filter( 'reycore/woocommerce/product_image/params', [$this, 'gallery_params'] );
		add_filter( 'woocommerce_single_product_zoom_enabled', '__return_false');
		add_filter( 'woocommerce_single_product_photoswipe_enabled', '__return_false');
		add_filter( 'woocommerce_product_thumbnails_columns', [$this, 'product_thumbnails_columns']);
		add_action( 'reycore/woocommerce/product_image/before_gallery', [$this, 'before_gallery']);
		add_action( 'reycore/woocommerce/product_image/before_gallery_wrapper', [$this, 'before_gallery_wrapper']);
		add_action( 'reycore/woocommerce/product_image/after_gallery_wrapper', [$this, 'after_gallery_wrapper']);
		add_action( 'woocommerce_product_thumbnails', [$this, 'before__woocommerce_product_thumbnails'], -1);
		add_action( 'woocommerce_product_thumbnails', [$this, 'remove_lazy_load_images'], 1000);
		add_filter( 'woocommerce_single_product_image_thumbnail_html', [$this, 'single_product_image_thumbnail_html'], 9, 2);
		add_action( 'reycore/woocommerce_single_product_image/before', [$this, 'before_main_image']);
		add_filter( 'woocommerce_gallery_image_size', [$this, 'thumbs_to_large_size']);

	}

	/**
	 * Product Page Component ID
	 *
	 * @return string
	 */
	public function get_id(){
		return 'gallery';
	}

	/**
	 * Product Page Component Name
	 *
	 * @return string
	 */
	public function get_name(){
		return 'Gallery';
	}

	public function render(){}

	/**
	 * Retrieve Gallery Types (for lists)
	 *
	 * @return array
	 */
	public function get_gallery_types(){

		$galleries = [];

		foreach ($this->galleries as $id => $gallery) {
			$galleries[ $id ] = $gallery->get_name();
		}

		return $galleries;
	}

	/**
	 * Retrieve Active Gallery type
	 *
	 * @return string
	 */
	public static function get_active_gallery_type(){
		return get_theme_mod('product_gallery_layout', 'vertical');
	}

	/**
	 * Preload the main image
	 *
	 * @return void
	 */
	public function preload_main_image(){

		if( ! is_product() ){
			return;
		}

		if( ! ($product = wc_get_product()) ){
			return;
		}

		if( ! ($image_id = $product->get_image_id()) ){
			return;
		}

		if( ! ($image_src = wp_get_attachment_image_src( $image_id, 'woocommerce_single' )) ){
			return;
		}

		printf('<link rel="preload" as="image" type="image/jpeg" href="%s"/>', $image_src[0]) . "\n";
	}

	/**
	 * Append CSS classes to Gallery
	 *
	 * @param array $classes
	 * @return array
	 */
	public function gallery_classes($classes)
	{

		$classes['gallery_type'] = 'woocommerce-product-gallery--' . esc_attr( self::get_active_gallery_type() );

		foreach ($this->galleries as $id => $gallery) {
			if( $id === self::get_active_gallery_type() ){
				$classes = array_merge($classes, $gallery->get_gallery_css_classes());
			}
		}

		if( get_theme_mod('product_gallery_preview_ratio', '') ){
			$classes['preview_ratio'] = '--preview-ratio';
		}

		if( get_theme_mod('pdp_img_radius', '') ){
			$classes['radius'] = '--radius';
		}

		if( get_theme_mod('product_page_gallery_mobile_peek', false) && ($product = wc_get_product()) && $product->get_gallery_image_ids() ){
			$classes['peek_mobile'] = '--peek-side-mobile';
		}

		/**
		 * `--default-variation-img` css class is used to determine if the page has loaded
		 * with a default variation selection.
		 */
		if( self::get_default_variation_image_id() ){
			$classes['loading'] = '--loading';
			$classes['is_variation'] = '--default-variation-img';
		}

		if( ! self::maybe_support_lazy_loading() ){
			$classes['no_lazy'] = '--no-rey-lazy';
		}

		if( self::is_gallery_with_thumbs() ){

			$classes['gallery_with_thumbs'] = '--gallery-thumbs';

			if( get_theme_mod('product_gallery_thumbs_flip', false) ){
				$classes['gallery_flip_thumbs'] = '--flip-thumbs';
			}

			if( get_theme_mod('product_gallery_thumbs_disable_cropping', false) ){
				$classes['gallery_thumbs_nocrop'] = '--thumbs-no-crop';
			}
		}

		if(
			self::is_gallery_with_thumbs() &&
			get_theme_mod('custom_main_image_height', false)
		){
			$classes['main-image-container-height'] = '--main-img-height';
		}

		if( ! self::mobile_gallery_enabled() ){
			$classes['no_mobile_gallery'] = '--no-mobile-gallery';
		}

		if( self::supports_animated_entries() ){
			$classes['animated_entries'] = '--supports-animated-entry';
		}

		if( ! self::is_lightbox_enabled() ){
			$classes['no_lightbox'] = '--no-lb';
		}

		return $classes;
	}

	public function body_classes( $frontend )
	{
		if( ! is_product() ){
			return;
		}

		if( self::is_gallery_with_thumbs() && ! get_theme_mod('product_page_summary_fixed__gallery', false) ){
			$frontend->remove_body_class(['fixed_summary', 'fixed_css_first', 'fixed_summary_gallery', 'fixed_summary_animate']);
		}

		$classes['gallery_type'] = '--gallery-' . self::get_active_gallery_type();

		$frontend->add_body_class($classes);

	}

	public function gallery_params($params)
	{

		$params['type'] = self::get_active_gallery_type();
		$params['zoom'] = get_theme_mod('product_page_gallery_zoom', true);
		$params['cascade_bullets'] = get_theme_mod('single_skin_cascade_bullets', true);
		$params['thumb_event'] = get_theme_mod('product_gallery_thumbs_event', 'click');
		$params['lightbox_captions'] = self::maybe_remove_image_title();
		$params['lightbox'] = self::is_lightbox_enabled();
		$params['photoswipe_options'] = apply_filters( 'woocommerce_single_product_photoswipe_options', [
			'shareEl'               => false,
			'closeOnScroll'         => false,
			'history'               => false,
			'hideAnimationDuration' => 0,
			'showAnimationDuration' => 0,
		] );
		$params['mobile_gallery_nav'] = self::get_mobile_nav_style();
		$params['loop'] = true;
		$params['autoheight'] = true;
		$params['autoheight_desktop'] = get_theme_mod('product_page_gallery_autoheight_desktop', true);
		$params['autoheight_mobile'] = get_theme_mod('product_page_gallery_autoheight_mobile', true);
		$params['start_index'] = 0;
		$params['lazy_images'] = self::maybe_support_lazy_loading();

		if( $product = wc_get_product() ){
			$params['product_page_id'] = $product->get_id();
			$params['product_main_image']['id'] = $product->get_image_id();
			$params['product_main_image']['src'] = wp_get_attachment_image_src( $params['product_main_image']['id'], apply_filters( 'woocommerce_gallery_full_size', apply_filters( 'woocommerce_product_thumbnails_large_size', 'full' ) ) );
			$params['product_main_image']['thumb'] = wp_get_attachment_image_src( $params['product_main_image']['id'], 'woocommerce_gallery_thumbnail' );
		}

		return $params;
	}

	/**
	 * Run before the gallery rendering
	 *
	 * @return void
	 */
	public function before_gallery()
	{

		add_action( 'wp_footer', [$this, 'wp_footer_after_gallery'] );

		$active_gallery_type = self::get_active_gallery_type();

		foreach ($this->galleries as $id => $gallery) {
			if( $id === $active_gallery_type ){
				$gallery->init( $this );
				$gallery->load_assets();
				reycore_assets()->add_styles( ['rey-wc-product-gallery', 'rey-wc-product-gallery-' . $id]);
			}
		}

	}

	/**
	 * Retrieve the count of the gallery items
	 *
	 * @return int
	 */
	public static function count_gallery_items(){
		return (int) apply_filters('reycore/woocommerce/pdp/gallery/items_count', count( reycore_wc__get_product_images_ids() ) );
	}

	/**
	 * Control number of columns thumbs in vertical/horizontal gallery
	 *
	 * * Does not influence mobile gallery (which can only be set with CSS)
	 *
	 * @param int $cols
	 * @return int
	 */
	public function product_thumbnails_columns($cols){
		/**
		 * For Vertical, it's intentionally not working.
		 * That's because the thumbs track is stretched and because of the flexible thumbs height,
		 * the height of the track cannot be properly calculated.
		 */
		if( $custom = get_theme_mod('product_gallery_thumbs_max', '') ){
			return absint($custom);
		}
		return $cols;
	}

	public function disable_thumbs_cropping($size){

		if( get_theme_mod('product_gallery_thumbs_disable_cropping', false) ){
			$size['height']  = 9999;
			$size['crop']   = false;
		}

		return $size;
	}

	public static function mobile_gallery_enabled(){
		return apply_filters('reycore/woocommerce/allow_mobile_gallery', true);
	}

	/**
	 * Load the gallery "thumbnails" as large images because
	 * all galleries use large format.
	 *
	 * @param string $size
	 * @return string
	 */
	public function thumbs_to_large_size($size) {
		return 'woocommerce_single';
	}

	/**
	 * Adds attributes to gallery images.
	 *
	 * @param array $attributes
	 * @return array
	 */
	public function filter_image_attributes( $attributes, $attachment_id, $image_size, $main_image ){

		$classes['default'] = '__img';
		$classes['image_type'] = '--gallery-img';

		// specify main image
		if( self::is_main_image_environment() ){
			$classes['image_type'] = '--main-img';
		}

		// prevent other plugins from trying to lazy load
		$classes['plugins_no_lazy'] = 'no-lazy';
		$attributes['data-skip-lazy'] = 1;
		$attributes['data-no-lazy'] = 1;

		if( $main_image ){
			$attributes['loading'] = 'eager';
		}

		if( self::maybe_remove_image_title() ){
			$attributes['title'] = '';
		}

		if( ! empty($attributes['class']) ){
			$attributes['class'] .= ' ';
			$attributes['class'] .= implode(' ', $classes);
		}
		else {
			$attributes['class'] = implode(' ', $classes);
		}

		return $attributes;

	}

	/**
	 * Adds lazy loading attributes to "thumbnails" (gallery images) images.
	 *
	 * @param array $attributes
	 * @return array
	 */
	public function set_thumbnails_lazy_load( $attributes ){

		$attributes['src'] = '';
		$attributes['loading'] = '';
		$attributes['data-rey-lazy-src'] = $attributes['data-src'];

		return $attributes;
	}

	/**
	 * Sets a global variable to indicate that the current image is the main image
	 *
	 * @return void
	 */
	public function set_main_image_environment(){
		$GLOBALS['gallery_is_main'] = true;
	}

	/**
	 * Removes the global variable that indicates that the current image is the main image
	 *
	 * @return void
	 */
	public function remove_main_image_environment(){
		unset($GLOBALS['gallery_is_main']);
	}

	/**
	 * Checks if the current image is the main image
	 *
	 * @return boolean
	 */
	public static function is_main_image_environment(){
		return ! empty($GLOBALS['gallery_is_main']);
	}

	/**
	 * Before the main image, or more exactly before
	 * the `reycore/woocommerce/single_product_image/before` hook
	 *
	 * @return void
	 */
	public function before_main_image(){
		$this->set_main_image_environment();
	}

	/**
	 * Before the gallery thumbnails's, or more exactly before
	 * the `woocommerce_product_thumbnails` hook
	 *
	 * @return void
	 */
	public function before__woocommerce_product_thumbnails(){
		$this->remove_main_image_environment();
		$this->set_lazy_load_images();
	}

	/**
	 * Force "thumbs" (gallery images) to lazy load
	 *
	 * @return void
	 */
	public function set_lazy_load_images( $bypass = false ) {

		if( $this->__added_lazy_loading && ! $bypass ){
			return;
		}

		if( ! self::maybe_support_lazy_loading() ){
			return;
		}

		add_filter( 'wp_calculate_image_srcset', '__return_false' );
		add_filter( 'woocommerce_gallery_image_html_attachment_image_params', [$this, 'set_thumbnails_lazy_load'], 30);

		$this->__added_lazy_loading = true;

	}

	/**
	 * Force "thumbs" (gallery images) to lazy load.
	 * Remove the hook
	 *
	 * @return void
	 */
	public function remove_lazy_load_images() {

		if( ! self::maybe_support_lazy_loading() ){
			return;
		}

		remove_filter( 'wp_calculate_image_srcset', '__return_false' );
		remove_filter( 'woocommerce_gallery_image_html_attachment_image_params', [$this, 'set_thumbnails_lazy_load'], 30);
	}

	/**
	 * Checks if the lightbox is enabled
	 *
	 * @return boolean
	 */
	public static function is_lightbox_enabled(){
		return get_theme_mod('product_page_gallery_lightbox', true);
	}

	public static function maybe_remove_image_title(){
		return apply_filters('reycore/woocommerce/pdp/gallery/remove_title', true);
	}

	public static function maybe_support_lazy_loading(){
		return apply_filters('reycore/woocommerce/pdp/gallery/lazy_loading', get_theme_mod('product_page_gallery__lazy_load', false));
	}

	public static function is_gallery_with_thumbs(){
		return apply_filters('reycore/woocommerce/pdp/gallery/with_thumbs', in_array( self::get_active_gallery_type(), ['vertical', 'horizontal'], true ));
	}

	public static function get_mobile_nav_style(){
		return get_theme_mod('product_gallery_mobile_nav_style', 'bars');
	}

	public static function supports_animated_entries(){
		return apply_filters('reycore/woocommerce/pdp/gallery/add_animation', in_array( self::get_active_gallery_type(), [
				'grid',
				'cascade',
				'cascade-scattered',
				'cascade-grid'
			], true)
		);
	}

	/**
	 * Detect and get the default selected variation's ID
	 *
	 * @return int
	 */
	public static function get_default_variation_id(){

		if( ! apply_filters('reycore/woocommerce/pdp/gallery/get_default_variation', true) ){
			return;
		}

		if( ! ($product = wc_get_product()) ){
			return;
		}

		// Ensure it's a variable product
		if ( ! $product->is_type( 'variable' ) ) {
			return;
		}

		/**
		 * @var \WC_Product_Variable $product
		 */

		static $variation_id;

		// Return cached value
		if( ! is_null($variation_id) ){
			return $variation_id;
		}

		$variation_id = 0;
		$default_attributes = $product->get_default_attributes(); // Get the default attributes

		if ( empty( $default_attributes ) ) { // Check if there are any default attributes
			return $variation_id;
		}

		$maybe_check_variation_attributes = false;

		if(
			($update_gallery_on_single_default = get_theme_mod('pdp_swatches__update_gallery', ''))
			&& ($update_gallery__attribute = wc_attribute_taxonomy_name( $update_gallery_on_single_default )) // prefix with pa_
			&& isset($default_attributes[ $update_gallery__attribute ]) // it's set as default
		){
			// will check the variation attributes for empty values
			$maybe_check_variation_attributes = true;
		}
		else {
			// get all parent product attributes used for variations
			$variation_attributes = $product->get_variation_attributes();
			// Check if all attributes are set in the default attributes array
			if( count($variation_attributes) !== count($default_attributes) ){
				return $variation_id;
			}
		}

		$prefixed_default_attributes = [];

		foreach ($default_attributes as $key => $value) {
			$prefixed_default_attributes['attribute_' . $key] = $value;
		}

		$variation_id = \WC_Data_Store::load( 'product' )->find_matching_product_variation( $product, $prefixed_default_attributes );

		if( $maybe_check_variation_attributes && $variation_id && ($variation = wc_get_product( $variation_id )) ){

			/**
			 * @var \WC_Product_Variation $variation
			 */
			$variation_attributes = array_filter($variation->get_variation_attributes());

			// if all of the variation attributes is empty, then it's not a valid variation
			if( empty($variation_attributes) ){
				$variation_id = 0;
			}

		}

		return $variation_id;
	}

	/**
	 * Detect and get the default selected variation's main image
	 *
	 * @return int
	 */
	public static function get_default_variation_image_id(){

		if( wp_doing_ajax() ){
			return;
		}

		static $variation_image_id;

		if( is_null( $variation_image_id ) ){

			$variation_image_id = 0;

			if( apply_filters('reycore/woocommerce/pdp/gallery/default_variation_swap', true) ){
				if( $variation_id = self::get_default_variation_id() ){
					if( $variation = wc_get_product( $variation_id ) ){
						// it's mandatory to have a main variation image
						if(
							($__variation_image_id = absint($variation->get_image_id())) &&
							// get main product
							($main_product = wc_get_product( $variation->get_parent_id() )) &&
							// ensure main product image is not the same as the variation
							$__variation_image_id !== absint($main_product->get_image_id())
						){
							$variation_image_id = $__variation_image_id;
						}

					}
				}
			}
		}

		return $variation_image_id;
	}


	/**
	 * Filter the gallery images html. Usually `wc_get_gallery_image_html` is wrapped in this hook so its markup can be modified.
	 *
	 * @param string $html
	 * @param int $post_thumbnail_id
	 * @return string
	 */
	public function single_product_image_thumbnail_html($html, $post_thumbnail_id){

		$is_main = self::is_main_image_environment();

		$index = isset($GLOBALS['pdp_gallery_item_count']) ? $GLOBALS['pdp_gallery_item_count'] : 0;

		// Add attributes to the main image wrapper
		// ensures it starts with <div

		$start_search_for = '<div ';
		$start_replace_with = '';

		// check for main image environment
		if( $is_main ){
			$start_replace_with .= 'data-main-item '; // specify main item attribute
			// ensure it's loaded
			if( ! wp_doing_ajax() && ! isset($GLOBALS['disable_image_loaded_attribute']) ){
				$start_replace_with .= 'data-image-loaded ';
			}
		}

		// increment index attribute
		$start_replace_with .= sprintf('data-index="%d" ', $index);

		// do the replacement
		if (substr($html, 0, 5) === $start_search_for) {
			$html = substr_replace($html, $start_search_for . apply_filters('reycore/woocommerce/pdp/gallery/item_attributes', $start_replace_with, $index), 0, 5);
		}

		// ------------------------------

		// add preloaders before ending anchor tag
		$html = str_replace( '</a>', '<span class="rey-lineLoader"></span></a>', $html );
		// ensure elementor's lightbox is disabled
		$link_attributes = 'data-elementor-open-lightbox="no" ';
		$link_attributes .= 'aria-haspopup="true" aria-expanded="false" ';
		$link_attributes .= sprintf('aria-label="%s" ', esc_html__('OPEN GALLERY', 'rey-core'));
		$html = str_replace( '<a ', '<a ' . $link_attributes, $html );

		// ------------------------------

		// Adds buttons
		// like video, lightbox etc.
		if (substr($html, -6) === '</div>') {

			ob_start();

			/**
			 * Fires before ending </div> tag.
			 * @since 2.8.0
			 */
			do_action('reycore/woocommerce/pdp/gallery/after_image', $this, $is_main, $post_thumbnail_id);

			// add lightbox button
			if( strpos($html, 'data-no-lightbox') === false ){
				self::render_lightbox_button();
			}

			// output is catched and appended to the html
			if( $action = ob_get_clean() ){
				$html = substr_replace($html, $action . '</div>', -6);
			}

		}

		if( isset($GLOBALS['pdp_gallery_item_count']) ){
			$GLOBALS['pdp_gallery_item_count']++;
		}

		return $html;
	}

	/**
	 * Render mobile navigation
	 *
	 * @return void
	 */
	public function before_gallery_wrapper(){

		$GLOBALS['pdp_gallery_item_count'] = 0;

		if( ! ($count = self::count_gallery_items()) ){
			return;
		}

		// no need navigations if just a single image
		if( $count <= 1 ){
			return;
		}

		// add preloader for various actions
		// hidden by default
		// echo '<div class="rey-lineLoader __gallery-loader"></div>';

		// start extra wrapper in order to properly
		// position the arrows vertically, in the middle
		echo '<div class="__topWrapper">';

	}

	/**
	 * Render mobile navigation
	 *
	 * @return void
	 */
	public function after_gallery_wrapper(){

		unset($GLOBALS['pdp_gallery_item_count']);

		if( ! ($count = self::count_gallery_items()) ){
			return;
		}

		// no need navigations if just a single image
		if( $count <= 1 ){
			return;
		}

		// Render counter
		self::add_counter_markup();

		// Render arrows
		self::add_arrows_navigation_markup();

		// close extra wrapper in order to properly
		// position the arrows vertically, in the middle
		// end .__topWrapper
		echo '</div>';

		$dots_nav = self::get_mobile_nav_style();

		// it's still added because it's likely to be used on mobile
		if( 'thumbs' !== $dots_nav ){
			// Dots Nav.
			$dots_nav_dots_classes[] = 'dotsNav';
			$dots_nav_dots_classes['nav_style'] = '--nav-' . $dots_nav;
			$dots_nav_dots_classes['hide_desktop'] = '--dnone-lg';
			$dots_nav_dots_classes = apply_filters('reycore/woocommerce/pdp/gallery/mobile_nav_classes', $dots_nav_dots_classes, $dots_nav);
			self::add_dots_navigation_markup(implode(' ', $dots_nav_dots_classes), false);
		}

		self::add_thumbs_navigation_markup();

	}

	/**
	 * Generate HTML markup for gallery navigation with thumbnails
	 *
	 * @return void
	 */
	public static function add_thumbs_navigation_markup(){

		if( ! ($count = self::count_gallery_items()) ){
			return;
		}

		$gallery_with_thumbs = self::is_gallery_with_thumbs();
		$mobile_with_thumbs = 'thumbs' === self::get_mobile_nav_style();

		if( ! ($gallery_with_thumbs || $mobile_with_thumbs) ){
			return;
		}

		$gallery_thumbnail = wc_get_image_size( 'gallery_thumbnail' );

		if( get_theme_mod('product_gallery_thumbs_disable_cropping', false) ){
			$gallery_thumbnail['height']  = 9999;
		}

		$thumbnail_size = apply_filters( 'woocommerce_gallery_thumbnail_size', [$gallery_thumbnail['width'], $gallery_thumbnail['height']] );

		$thumbs = [];

		$i = 0;

		foreach ( apply_filters('reycore/woocommerce/pdp/gallery/thumbnail_items', reycore_wc__get_product_images_ids() ) as $key => $image_id) {

			$uses_image_id = false !== $image_id;

			add_filter( 'wp_calculate_image_srcset', '__return_false' );

			$thumb_image_attributes = [
				'class' => 'woocommerce-product-gallery__mobile-img',
			];

			if( self::maybe_support_lazy_loading() ){
				$thumb_image_attributes['loading'] = '';
				$thumb_image_attributes['src'] = '';
				$thumb_image_attributes['data-rey-lazy-src'] = $uses_image_id ?
					wp_get_attachment_image_url($image_id, $thumbnail_size) :
					wc_placeholder_img_src( 'woocommerce_single' );
			}

			$thumb_image = $uses_image_id ?
				wp_get_attachment_image($image_id, $thumbnail_size, false, $thumb_image_attributes) :
				wc_placeholder_img('woocommerce_single', $thumb_image_attributes);

			// prefix preloader
			if( self::maybe_support_lazy_loading() ){
				$thumb_image .= '<div class="rey-lineLoader"></div>';
			}

			$thumb = sprintf('<button class="__thumbItem %s" data-index="%d" aria-label="%s" tabindex="-1">%s</button>',
				($i === 0 ? '--active' : ''),
				$i,
				esc_html__('Go to ', 'rey-core') . ($i+1),
				$thumb_image
			);

			remove_filter( 'wp_calculate_image_srcset', '__return_false' );

			$thumbs[] = apply_filters('reycore/woocommerce/product_mobile_gallery/slide_html', $thumb, $image_id, $key);

			$i++;
		}

		$wrapper_classes = [];

		if( $gallery_with_thumbs ){
			$wrapper_classes[] = '--thumbs-gallery';
		}

		if( $mobile_with_thumbs ){
			$wrapper_classes[] = '--mobile-thumbs';
		}

		$wrapper_classes['gallery_thumbs_style'] = '--thumbs-arr-' . esc_attr(get_theme_mod('product_gallery_thumbs_nav_style', 'boxed'));

		$disabled_attribute_prev = 'data-disabled';
		$disabled_attribute_next = '';

		if( is_rtl() ){
			$disabled_attribute_prev = '';
			$disabled_attribute_next = 'data-disabled';
		}

		$nav_arrows = sprintf('<button data-dir="<" %3$s aria-label="%1$s" tabindex="-1">%2$s</button>', esc_html__('Previous', 'rey-core'), reycore__get_svg_icon(['id' => 'arrow']), $disabled_attribute_prev);
		$nav_arrows .= sprintf('<button data-dir=">" %3$s aria-label="%1$s" tabindex="-1">%2$s</button>', esc_html__('Next', 'rey-core'), reycore__get_svg_icon(['id' => 'arrow']), $disabled_attribute_next);

		// On horizontal, when max thumbs is larger than the published thumbs
		if( self::get_active_gallery_type() === 'horizontal' ){
			if( ($max_thumbs = get_theme_mod('product_gallery_thumbs_max', '')) && count($thumbs) <= $max_thumbs ){
				$wrapper_classes[] = '--j-center';
			}
		}

		return printf('<div class="__thumbs-wrapper %s"><div class="__thumbs-track" data-count="%s">%s</div><div class="__thumbs-arr">%s</div></div>',
			implode(' ', $wrapper_classes),
			count($thumbs),
			implode('', $thumbs),
			$nav_arrows
		);

	}

	/**
	 * Generate HTML markup for gallery navigation
	 *
	 * @param string $wrapper_class
	 * @param boolean $scroll_item
	 * @return void
	 */
	public static function add_dots_navigation_markup($wrapper_class = '', $after = ''){

		if( ! ($count = self::count_gallery_items()) ){
			return;
		}

		$bullets = [];

		for ($i=0; $i < $count; $i++) {
			$bullets[] = sprintf('<button class="__navItem %s" data-index="%d" aria-label="%s"></button>', ($i === 0 ? "--active" : ""), $i, esc_html__('Go to image', 'rey-core'),);
		}

		printf('<div class="__nav-wrapper %1$s" data-count="%4$d"><div class="__nav">%2$s</div>%3$s</div>',
			$wrapper_class,
			implode('', $bullets),
			$after,
			$count
		);

	}

	/**
	 * Generate HTML markup for counter (1/5)
	 *
	 * @return void
	 */
	public static function add_counter_markup(){

		if( ! get_theme_mod('product_gallery_counter_data', false) ){
			return;
		}

		printf(
			'<div class="__counter-wrapper"><span class="__current">%s</span>/<span class="__total">%s</span></div>',
			1,
			self::count_gallery_items()
		);

	}

	/**
	 * Generate HTML markup for arrows navigation
	 *
	 * @return void
	 */
	public static function add_arrows_navigation_markup(){

		if( ! ($count = self::count_gallery_items()) ){
			return;
		}

		$cond[] = get_theme_mod('product_page_gallery_arrow_nav', false) && self::is_gallery_with_thumbs();
		$cond[] = get_theme_mod('product_gallery_mobile_arrows', false);

		if( ! in_array(true, $cond, true) ){
			return;
		}

		printf(
			'<div class="__arr-wrapper">%1$s</div>',
			reycore__svg_arrows([
				'attributes' => [
					'left' => sprintf('data-dir="<" aria-label="%s"', esc_html__('Previous', 'rey-core')),
					'right' => sprintf('data-dir=">" aria-label="%s"', esc_html__('Next', 'rey-core')),
				],
				'tag' => 'button',
				'echo' => false,
				'name' => 'pdp_gallery_arrows',
			])
		);

	}

	public function wp_footer_after_gallery(){
		$this->add_delay_js_hack();
		$this->add_photoswipe_template();
	}

	/**
	 * Hack to force load the JS, when delayed JS is enabled. This prevents the gallery to remain in loading state, as if it's stuck, until the visitor makes any event.
	 * Should happen only if a variation is set as default and has a different image vs. main one.
	 *
	 * @return void
	 */
	public function add_delay_js_hack(){

		if( ! is_product() ){
			return;
		}

		if( ! apply_filters('reycore/woocommerce/pdp/gallery/delayed_js_preselected_variation_instant_load', reycore__js_is_delayed() && self::get_default_variation_image_id()) ){
			return;
		}

		echo '<script type="text/javascript" id="reycore-gallery-has-default" data-noptimize="" data-no-optimize="1" data-no-defer="1" data-pagespeed-no-defer=""> setTimeout(()=>{window.dispatchEvent(new Event("mousemove")); console.log("Force load JS because of the pre-selected variation in the gallery.")}, 100);</script>';

	}

	/**
	 * Adds the Photoswipe template.
	 * Also creates a global variable with the assets paths in order to be downloaded on request.
	 *
	 * @return void
	 */
	public function add_photoswipe_template(){

		wc_get_template( 'single-product/photoswipe.php' );

		$assets = [
			'styles' => ['photoswipe', 'photoswipe-default-skin'],
			'scripts' => ['photoswipe', 'photoswipe-ui-default'],
		];

		$assets_with_paths = [];

		if( wp_doing_ajax() ){
			do_action('wp_enqueue_scripts');
		}

		foreach ($assets as $type => $handles) {
			foreach ($handles as $handle) {
				if ('styles' === $type && wp_style_is($handle, 'registered')) {
					$assets_with_paths[$type][$handle] = wp_styles()->registered[$handle]->src . '?ver=' . REY_CORE_VERSION;
				}
				elseif ('scripts' === $type && wp_script_is($handle, 'registered')) {
					$assets_with_paths[$type][$handle] = wp_scripts()->registered[$handle]->src . '?ver=' . wp_scripts()->registered[$handle]->ver;
				}
			}
		}

		if( empty($assets_with_paths['styles']) || empty($assets_with_paths['scripts']) ){
			return;
		}

		printf('<script type="text/javascript">var PS_scripts_styles = %s;</script>', wp_json_encode($assets_with_paths));

	}

	public static function render_lightbox_button(){

		if( ! self::is_lightbox_enabled() ){
			return;
		}

		if( ! get_theme_mod('product_page_gallery__btn__enable', true) ){
			return;
		}

		$classes = ['rey-openBtn', '__lightbox-btn', 'btn'];
		$btn_text = get_theme_mod('product_page_gallery__btn__text', esc_html__('OPEN GALLERY', 'rey-core'));
		$btn_content = '';

		// text
		if( get_theme_mod('product_page_gallery__btn__text_enable', false) ){
			$classes[] = '--has-text';
			$btn_content .= '<span class="__lightbox-btnContent">' . $btn_text . '</span>';
		}

		// icon
		if( $icon = get_theme_mod('product_page_gallery__btn__icon', 'plus-stroke') ){
			$classes[] = '--has-icon';
			$btn_content .= reycore__get_svg_icon(['id' => 'reycore-icon-' . $icon]);
		}

		printf('<button class="%3$s" title="%2$s" aria-label="%2$s" role="button">%1$s</button>',
			$btn_content,
			$btn_text,
			implode(' ', $classes)
		);

	}

	public function append_delay_js_exclusions($scripts) {
		return array_merge($scripts, ['reycore-gallery-has-default' => 'reycore-gallery-has-default']);
	}

	/**
	 * Include PSWP template in quickview response
	 *
	 * @param array $return
	 * @param array $data
	 * @return array
	 */
	public function include_pswp_in_quickview( $return, $data ){

		if( ! (isset($data['pswp']) && ! absint($data['pswp'])) ){
			return $return;
		}

		ob_start();
		$this->add_photoswipe_template();
		$return['pswp'] = ob_get_clean();

		return $return;
	}

}