<?php
/**
 * WooProducts
 * 
 * Powerful element to showcase
 * your products in different layouts.
 * 
 * @since 1.0.0
 */

namespace OKThemes\Toolkit\Elementor\Widgets\WooCommerce;

use Elementor\Controls_Manager;
use Elementor\Icons_Manager;

use OKThemes\Toolkit\Elementor\Helpers\Products as Products_Helper;
use Elementor\Widget_Base;

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

class Products extends Widget_Base {

	protected $query_args;

	protected $terms = [];

	public function get_name() {
		return 'okthemes-woo-products';
	}

	public function get_title() {
		return __( 'OKT - WooProducts', 'okthemes-toolkit' );
	}

	public function get_icon() {
		return 'eicon-products';
	}

	public function get_script_depends() {
		return [ 'imagesloaded', 'okthemes-products-carousel','okthemes-masonry-metro' ];
	}

	public function get_categories() {
		return ['okthemes_elements'];
	}

	protected function register_controls() {
		new Products_Helper( $this );
	}

	public function get_style_depends() {
		if ( Icons_Manager::is_migration_allowed() ) {
			return [
				'elementor-icons-fa-solid',
				'elementor-icons-fa-brands',
			];
		}
		return [];
	}

	/**
	 * Post Thumbnail
	 * 
	 * Displays the image on the top
	 * of article if the image position
	 * is not set at none and show image.
	 * 
	 * @since 1.0.0
	 */
	protected function get_post_thumbnail() {
		if ( ! has_post_thumbnail() || ( $this->get_settings( 'image_position' ) == 'none'  && ! \Elementor\Plugin::$instance->editor->is_edit_mode() ) || ( ! $this->get_settings( 'show_image' ) && $this->get_settings( 'skin' ) == 'cards' ) ) {
			return;
		}

		if ( $this->get_settings( 'image_size_size' ) == 'custom' && !empty ( $this->get_settings( 'image_size_custom_dimension' )['width'] ) && ! empty ( $this->get_settings( 'image_size_custom_dimension' )['height'] ) ) {
			$image_size = [
				$this->get_settings( 'image_size_custom_dimension' )['width'],
				$this->get_settings( 'image_size_custom_dimension' )['height']
			];
		} else {
			$image_size = $this->get_settings( 'image_size_size' );
		}

		// Metro Image Calculation
		$isMetroMasonry = $this->get_settings( 'layout' ) == 'masonry' || $this->get_settings( 'layout' ) == 'metro';
		$padding_bottom = '';

		if ( $isMetroMasonry ) {
			$attachment_id = get_post_thumbnail_id( get_the_ID() ); 
			$metadata = wp_get_attachment_metadata( $attachment_id );
			$height =  $metadata['height'];
			$width =  $metadata['width'];
			$padding_bottom = 'style="padding-bottom: ' . round( ( $height / $width) * 100 ) . '%;"';
		}

		$output = '';
		$output .= '<a class="m-okthemes-post__thumbnail--link" '. $padding_bottom .' href="'. get_the_permalink() .'">';
		$output .= $this->get_product_overlay();
		$output .= '<div class="m-okthemes-post__thumbnail m-okthemes-product__thumbnail">';
		$output .= get_the_post_thumbnail( get_the_ID(), $image_size );
		
		// Secondary Image
		global $product;

		if ( $this->get_settings( 'image_hover_secondary' ) == 'yes' && ! empty( $product->get_gallery_image_ids() ) ) {
			$output .= '<div class="m-okthemes-post__thumbnail--secondary" style="background-image: url('. wp_get_attachment_url( $product->get_gallery_image_ids()[0] ) .');"></div>';
		}

		$output .= '</div>';
		$output .= '</a>';

		return $output;
	}

	/**
	 * Product Overlay
	 * 
	 * @since 1.0.0
	 */
	protected function get_product_overlay() {
		$output = [];

		if ( $this->get_settings( 'add_to_cart_position' ) == 'inside' ) {
			$output[] = $this->add_to_cart();
		}

		if ( empty( $output ) ) {
			return;
		}

		return '<div class="m-okthemes-product__overlay">' . implode( ' ', $output ) . '</div>';
	}

	/**
	 * Product Cart
	 * 
	 * Print outside
	 * the cart.
	 * 
	 * @since 1.0.0
	 */
	protected function get_product_cart() {
		if ( $this->get_settings( 'add_to_cart_position' ) != 'outside' ) {
			return;
		}

		return $this->add_to_cart();
	}

	/**
	 * Get Rating
	 * 
	 * Display product rating.
	 * 
	 * @since 1.0.0
	 */
	protected function get_rating() {
		$product = wc_get_product( get_the_ID() );

		if ( empty ( $product ) ) {
			return;
		}

		$rating_count = $product->get_rating_count();

		if ( $this->get_settings( 'rating' ) != 'yes' || $rating_count == 0 ) {
			return;
		}
		?>
			<div class="m-okthemes-product__rating">
				<div class="woocommerce"><?php woocommerce_template_single_rating(); ?></div>
			</div>
		<?php
	}

	/**
	 * Get Price
	 * 
	 * Get price if the source
	 * is product.
	 * 
	 * @since 1.0.0
	 */
	protected function get_price() {
		global $product;

		if ( $this->get_settings( 'price' ) != 'yes' || empty( $product ) ) {
			return;
		}

		$price_html = $product->get_price_html();

		if ( $price_html ) {
			return '<span class="m-okthemes-product__price">'. wp_kses_post( $price_html ) .'</span>';
		}
	}

	/**
	 * Add to Cart
	 * 
	 * Display add to cart
	 * button which user is able
	 * via ajax to add the product
	 * to his/her mini cart.
	 * 
	 * @since 1.0.0
	 */
	protected function add_to_cart() {
		if ( $this->get_settings( 'add_to_cart' ) != 'yes' ) {
			return;
		}

		$add_to_cart_text = $this->get_settings( 'add_to_cart_text' );

		global $product;

		if ( ! empty ( $product ) ) {
			if ( ( ! $product->is_in_stock() || ! $product->is_purchasable() ) && ! is_single() ) {
				$output = sprintf(
					'<a class="product_type_%s button" href="%s">
						%s
					</a>',
					esc_attr( $product->get_type() ),
					$product->is_type( 'external' ) ? esc_url( $product->add_to_cart_url() ) : esc_url( get_the_permalink() ),
					$product->is_type( 'external' ) ? esc_html__( 'Buy Product', 'okthemes-toolkit' ) : esc_html__( 'Read More', 'okthemes-toolkit' )
				);
			} else if ( $product->is_purchasable() && $product->is_in_stock() ) {
				$output = apply_filters( 'woocommerce_loop_add_to_cart_link',
				sprintf( 
					'<a href="%s" rel="nofollow" data-product_id="%s" data-product_sku="%s" class="button ajax_add_to_cart add_to_cart_button product_type_%s">
							%s
						</a>',
					esc_url( $product->add_to_cart_url() ),
					esc_attr( $product->get_id() ),
					esc_attr( $product->get_sku() ),
					esc_attr( $product->get_type() ),
					$add_to_cart_text ? '<span>'. $add_to_cart_text .'</span>' : ''
				),
			$product );
			}
		}

		if ( ! empty ( $output ) ) {
			return '<span class="m-okthemes-product__add-to-cart">'. $output .'</span>';
		}
	}

	/**
	 * Flash Sale
	 * 
	 * A flash sale badge which
	 * is displayed on the top
	 * of product when there's
	 * a sale onto it.
	 * 
	 * @since 1.0.0
	 */
	protected function sale_flash() {
		if ( $this->get_settings( 'sale_flash' ) != 'yes' || $this->get_settings( 'carousel' ) == 'yes' ) {
			return;
		}

		global $product;

		if ( $product->is_on_sale() ) {
			return '<span class="m-okthemes-product__sale-flash">'. esc_html__( 'Sale', 'okthemes-toolkit' ) .'</span>';
		}
	}

	/**
	 * Orderby Sorting
	 * 
	 * Sort by WooCommerce options
	 * 
	 * @since 1.0.0
	 */
	protected function query_by_woo_orderby() {
		if ( $this->get_settings( 'allow_order' ) != 'yes' && $this->get_settings( 'results_count' ) != 'yes' ) {
			return;
		}

		/**
		 * Catalog Orderby
		 */
		$orderby_options = apply_filters(
			'woocommerce_catalog_orderby',
			array(
				'menu_order' => __( 'Default sorting', 'okthemes-toolkit' ),
				'popularity' => __( 'Sort by popularity', 'okthemes-toolkit' ),
				'rating'     => __( 'Sort by average rating', 'okthemes-toolkit' ),
				'date'       => __( 'Sort by newness', 'okthemes-toolkit' ),
				'price'      => __( 'Sort by price: low to high', 'okthemes-toolkit' ),
				'price-desc' => __( 'Sort by price: high to low', 'okthemes-toolkit' )
			)
		);

		$default_orderby = wc_get_loop_prop( 'is_search' ) ? 'relevance' : apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby', '' ) );

		$this->catalog_orderby_options = apply_filters( 'woocommerce_catalog_orderby', $orderby_options );

		/**
		 * Change default order
		 */
		if ( isset( $_GET['orderby'] ) ) {
			$orderby = isset( $_GET['orderby'] ) ? wc_clean( wp_unslash( $_GET['orderby'] ) ) : $default_orderby;
			$show_default_orderby = 'default';
		} else {
			switch ( $this->get_settings( 'posts_meta_ordering_default' ) ) {
				default:
					$show_default_orderby = $orderby = 'menu_order';
					break;
				case 'popularity':
					$show_default_orderby = $orderby = 'popularity';
					break;
				case 'rating':
					$show_default_orderby = $orderby = 'rating';
					break;
				case 'date':
					$show_default_orderby = $orderby = 'date';
					break;
				case 'price':
					$show_default_orderby = $orderby = 'price';
					break;
				case 'price-desc':
					$show_default_orderby = $orderby = 'price-desc';
					break;
			}
		}

		$this->orderby = $orderby;
		$this->show_default_orderby = $show_default_orderby;

		/**
		 * Modify Query for Orderby
		 */
		switch ( $this->orderby ) {
			case 'default':
				$this->query_args['orderby'] = 'menu_order';
				$this->query_args['order'] = 'asc';
				break;
			case 'popularity':
				$this->query_args['orderby'] = 'meta_value_num';
				$this->query_args['meta_key'] = 'total_sales';
				$this->query_args['order'] = 'desc';
				break;
			case 'rating':
				$this->query_args['orderby'] = 'meta_value_num';
				$this->query_args['meta_key'] = '_wc_average_rating';
				$this->query_args['order'] = 'desc';
				break;
			case 'date':
				$this->query_args['orderby'] = 'date';
				$this->query_args['meta_key'] = '';
				$this->query_args['order'] = 'desc';
				break;
			case 'price':
				$this->query_args['orderby'] = 'meta_value_num';
				$this->query_args['meta_key'] = '_price';
				$this->query_args['order'] = 'asc';
				break;
			case 'price-desc':
				$this->query_args['orderby'] = 'meta_value_num';
				$this->query_args['meta_key'] = '_price';
				$this->query_args['order'] = 'desc';
				break;
		}
	}

	/**
	 * Top Bar
	 * 
	 * Includes WooCommerce orderby
	 * and results count of woocommerce.
	 * 
	 * @since 1.0.0
	 */
	protected function woo_top_bar( $query ) {
		if ( $this->get_settings( 'allow_order' ) != 'yes' && $this->get_settings( 'results_count' ) != 'yes' ) {
			return;
		}

		/**
		 * Result Count
		 */
		$okthemes_result_count_args = [
			'total'    => $query->found_posts,
			'per_page' => $this->query_args['posts_per_page'] ? $this->query_args['posts_per_page'] : 10,
			'current'  => $this->get_paged(),
		];

		?>
		<div class="m-okthemes-product__woo-bar">
			<?php if ( $this->get_settings( 'results_count' ) == 'yes' ) : ?>
				<?php wc_get_template('loop/result-count.php', $okthemes_result_count_args) ?>
			<?php endif; ?>
			<?php if ( $this->get_settings( 'allow_order' ) == 'yes' ) : ?>
				<?php 
					wc_get_template('loop/orderby.php', array(
						'catalog_orderby_options' => $this->catalog_orderby_options,
						'orderby' => $this->orderby,
						'show_default_orderby' => $this->show_default_orderby,
					));
				?>
			<?php endif; ?>
		</div>
		<?php
	}

	/**
	 * Paged
	 * 
	 * @since 1.0.0
	 */
	protected function get_paged() {
		if ( get_query_var( 'paged' ) ) {
			$paged = get_query_var( 'paged' );
		} elseif ( get_query_var( 'page' ) ) {
			$paged = get_query_var( 'page' );
		} else {
			$paged = 1;
		}

		return $paged;
	}

	/**
	 * Query by Source
	 * 
	 * @since 1.0.0
	 */
	protected function query_by_source() {
		$source = $this->get_settings( 'source' );

		if ( $source == 'sale' ) {
			$this->query_args['meta_query'] = [
				'relation' => 'OR',
				array( // Simple products type
					'key'     => '_sale_price',
					'value'   => 0,
					'compare' => '>',
					'type'    => 'numeric'
				),
				array( // Variable products type
					'key'     => '_min_variation_sale_price',
					'value'   => 0,
					'compare' => '>',
					'type'    => 'numeric'
				)
			];
		} elseif ( $source == 'featured' ) {
			$this->query_args['tax_query'] = [
				[
					'taxonomy' => 'product_visibility',
					'field'    => 'name',
					'terms'    => 'featured',
					'operator' => 'IN'
				],
			];			
		}
	}

	/**
	 * Include By Term
	 * 
	 * Include post that contains
	 * the following term.
	 * 
	 * @since 1.0.0
	 */
	protected function include_by_term() {
		$include = $this->get_settings( 'include_by' );
		$include_term = $this->get_settings( 'include_term' );

		if ( empty ( $include ) || ! in_array( 'term', $include ) || empty( $include_term  ) ) {
			return;
		}

		$this->query_args['tax_query']['relation'] = 'OR';

		foreach ( $include_term as $term ) {
			$termSingle = strstr( $term, '==', false );
			$termType = strstr( $term, '==', true );
			$termObj = str_replace( '==', '', $termSingle );

			$this->query_args['tax_query'][] = [
				'taxonomy' => $termType,
				'terms' => $termObj,
				'field' => 'slug'
			];
		}
	}

	/**
	 * Exclude By Term
	 * 
	 * Include post that contains
	 * the following term.
	 * 
	 * @since 1.0.0
	 */
	protected function exclude_by_term() {
		$exclude = $this->get_settings( 'exclude_by' );
		$exclude_term = $this->get_settings( 'exclude_term' );

		if ( empty ( $exclude ) || ! in_array( 'term', $exclude ) || empty( $exclude_term  ) ) {
			return;
		}

		foreach ( $exclude_term as $term ) {
			$termSingle = strstr( $term, '==', false );
			$termType = strstr( $term, '==', true );
			$termObj = str_replace( '==', '', $termSingle );

			$this->query_args['tax_query'][] = [
				'taxonomy' => $termType,
				'terms' => $termObj,
				'field' => 'slug',
				'operator' => 'NOT IN'
			];
		}

		// Handle Relation
		if ( ! empty ( $this->get_settings( 'include_by' ) ) || in_array( 'term', $this->get_settings( 'include_by' ) ) ) {
			$this->query_args['tax_query']['relation'] = 'AND';
		}
	}

	/**
	 * Include Manually
	 * 
	 * Include manually any kind
	 * of page or post to the query.
	 * 
	 * @since 1.0.0
	 */
	protected function include_manually() {
		if ( $this->get_settings( 'source' ) != 'manual-selection' || empty ( $this->get_settings('search_select') ) ) {
			return;
		}

		foreach ( $this->get_settings('search_select') as $term ) {
			$termSingle = strstr( $term, '-', false );
			$termType = strstr( $term, '-', true );
			$termObj = str_replace( '-', '', $termSingle );

			$this->query_args['post__in'][] = $termObj;
		}
	}

	/**
	 * Exclude Manually
	 * 
	 * Exclude manually any kind
	 * of page or post to the query.
	 * 
	 * @since 1.0.0
	 */
	protected function exclude_manually() {
		$exclude = $this->get_settings( 'exclude_by' );
		$exclude_term = $this->get_settings( 'exclude_term' );

		if ( ( empty ( $exclude ) || ! in_array( 'term', $exclude ) || empty( $exclude_term  ) ) && empty( $this->get_settings( 'exclude_manual' ) ) ) {
			return;
		}

		foreach ( $this->get_settings( 'exclude_manual' ) as $term ) {
			$termSingle = strstr( $term, '-', false );
			$termType = strstr( $term, '-', true );
			$termObj = str_replace( '-', '', $termSingle );

			$this->query_args['post__not_in'][] = $termObj;
		}
	}

	/**
	 * Query By Author
	 * 
	 * Include or Exclude posts
	 * by a certain author.
	 * 
	 * @since 1.0.0
	 */
	protected function query_by_author() {
		// Include
		if ( ! empty ( $this->get_settings( 'include_by' ) ) && in_array( 'author', $this->get_settings( 'include_by' ) ) && ! empty( $this->get_settings( 'include_author' ) ) ) {
			$this->query_args['author'] = implode(', ', $this->get_settings( 'include_author' ) );
		}

		// Exclude
		if ( ! empty ( $this->get_settings( 'exclude_by' ) ) &&  in_array( 'author', $this->get_settings( 'exclude_by' ) ) && ! empty( $this->get_settings( 'exclude_author' ) )  ) {
			$this->query_args['author__not_in'] = implode(', ', $this->get_settings( 'exclude_author' ) );
		}
	}

	/**
	 * Exclude Curent Post
	 * 
	 * @since 1.0.0
	 */
	protected function query_exclude_current_post() {
		if ( ! empty ( $this->get_settings( 'exclude_by' ) ) && ( in_array( 'current-post', $this->get_settings( 'exclude_by' ) ) ) ) {
			if ( ! empty ( $this->query_args['post__not_in'] ) ) {
				$this->query_args['post__not_in'] = array_push( $this->query_args['post__not_in'], get_the_ID() );
			} else {
				$this->query_args['post__not_in'] = [get_the_ID()];
			}
		}
	}

	/**
	 * Query By Date
	 * 
	 * Include posts that have
	 * a certain time creation.
	 * 
	 * @since 1.0.0
	 */
	function query_by_date() {
		if ( $this->get_settings( 'source' ) == 'manual-selection' || $this->get_settings( 'date_order' ) == 'all' ) {
			return;
		}

		switch ( $this->get_settings( 'date_order' ) ) {
			case 'past-day':
				$this->query_args['date_query'] = ['after' => '-1 day'];
				break;
			case 'past-week':
				$this->query_args['date_query'] = ['after' => '-1 week'];
				break;
			case 'past-month':
				$this->query_args['date_query'] = ['after' => '-1 month'];
				break;
			case 'past-quarter':
				$this->query_args['date_query'] = ['after' => '-3 month'];
				break;
			case 'past-year':
				$this->query_args['date_query'] = ['after' => '-1 year'];
				break;
		}

		if ( $this->get_settings( 'date_order' ) == 'custom' ) {
			$this->query_args['date_query']['inclusive'] = 1;
			
			if ( $this->get_settings( 'date_before' ) ) {
				$this->query_args['date_query']['before'] = $this->get_settings( 'date_before' );
			}

			if ( $this->get_settings( 'date_after' ) ) {
				$this->query_args['date_query']['after'] = $this->get_settings( 'date_after' );
			}
		}
	}

	/**
	 * Query Products
	 * 
	 * Different properties to the wp_query
	 * to extend the query with includes
	 * and excludes.
	 * 
	 * @since 1.0.0
	 */
	protected function query_posts() {
		$this->query_by_source();

		$this->query_by_author();
		$this->include_by_term();
		$this->include_manually();

		$this->exclude_by_term();
		$this->exclude_manually();
		$this->query_exclude_current_post();

		$this->query_by_date();

		// WooCommerce
		$this->query_by_woo_orderby();
	}

	/**
	 * Show More Pagination
	 * 
	 * Includes and Excludes
	 * posts to display them
	 * via the ajax pagination.
	 * 
	 * @since 1.0.0
	 */
	protected function show_more_pagination() {
		if ( $this->get_settings( 'pagination' ) != 'show-more' ) {
			return;
		}

		$filter = isset( $_GET['filter'] ) ? $_GET['filter'] : '';
		$taxonomy = isset( $_GET['termType'] ) ? $_GET['termType'] : '';
		$exclude = isset( $_GET['exclude'] ) ? $_GET['exclude'] : '';

		if ( $filter ) {
			$this->query_args['tax_query'] = array(
				array(
					'taxonomy' => $taxonomy ? $taxonomy : 'category',
					'field' => 'slug',
					'terms' => $filter
				)
			);
		}

		if ( $exclude ) {
			$this->query_args['post__not_in'] = $exclude;
		}
	}

	/**
	 * Query
	 * 
	 * Loads the query with
	 * different sources and
	 * works with include &
	 * exclude option on it.
	 * 
	 * @since 1.0.0
	 */
	protected function get_query( $filters = false ) {
		$this->query_args = [
			'post_type' => 'product',
			'posts_per_page' => $this->get_settings('posts_per_page') ? $this->get_settings('posts_per_page') : 6,
			'paged' => $this->get_paged(),
			'orderby' => $this->get_settings( 'orderby' ),
			'order' => $this->get_settings( 'order' ),
			'ignore_sticky_posts' => $this->get_settings( 'ignore_sticky' ) == 'yes' ? 1 : '',
			'offset' => $this->get_settings( 'query_offset' ),
		];

		if ( $this->get_settings('source') == 'current_query' ) {
			$this->query_args = $GLOBALS['wp_query']->query_vars;
		}

		$this->query_posts();

		// Filters
		if ( ! $filters ) {
			$this->show_more_pagination();
		}

		$product_visibility_term_ids = wc_get_product_visibility_term_ids();

		// Show/Hide out of stock
		if ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ) {
			$this->query_args['tax_query'][] = array(
				array(
					'taxonomy' => 'product_visibility',
					'field'    => 'term_taxonomy_id',
					'terms'    => $product_visibility_term_ids['outofstock'],
					'operator' => 'NOT IN',
				),
			); // WPCS: slow query ok.
		}

		$query = new \WP_Query( $this->query_args );

		return $query;
	}

	/**
	 * Get Current Page
	 * 
	 * @since 1.0.0
	 */
	public function get_current_page() {
		if ( '' === $this->get_settings( 'pagination' ) ) {
			return 1;
		}

		return max( 1, get_query_var( 'paged' ), get_query_var( 'page' ) );
	}

	/**
	 * Get WP Link Page
	 * 
	 * @since 1.0.0
	 */
	private function get_wp_link_page( $i ) {
		if ( ! is_singular() || is_front_page() ) {
			return get_pagenum_link( $i );
		}

		global $wp_rewrite;
		$post = get_post();
		$query_args = [];
		$url = get_permalink();

		if ( $i > 1 ) {
			if ( '' === get_option( 'permalink_structure' ) || in_array( $post->post_status, [ 'draft', 'pending' ] ) ) {
				$url = add_query_arg( 'page', $i, $url );
			} else {
				$url = trailingslashit( $url ) . user_trailingslashit( "$wp_rewrite->pagination_base/" . $i, 'single_paged' );
			}
		}

		if ( is_preview() ) {
			if ( ( 'draft' !== $post->post_status ) && isset( $_GET['preview_id'], $_GET['preview_nonce'] ) ) {
				$query_args['preview_id'] = wp_unslash( $_GET['preview_id'] );
				$query_args['preview_nonce'] = wp_unslash( $_GET['preview_nonce'] );
			}

			$url = get_preview_post_link( $post, $query_args, $url );
		}

		return $url;
	}

	public function get_posts_nav_link( $page_limit = null ) {
		if ( ! $page_limit ) {
			$page_limit = $this->query->max_num_pages;
		}

		$return = [];

		$paged = $this->get_current_page();

		$link_template = '<a class="page-numbers %s page-label" href="%s">%s</a>';
		$disabled_template = '<span class="page-numbers %s page-label">%s</span>';

		ob_start();

		Icons_Manager::render_icon( $this->get_settings( 'label_icon' ) );

		$label_icon = '<span class="m-okthemes-pagination--icon">' . ob_get_contents() . '</span>';

		ob_end_clean();

		if ( $paged > 1 ) {
			$next_page = intval( $paged ) - 1;
			if ( $next_page < 1 ) {
				$next_page = 1;
			}

			$return['prev'] = sprintf( $link_template, 'prev', $this->get_wp_link_page( $next_page ), $label_icon . $this->get_settings( 'previous_label' ) );
		} else {
			$return['prev'] = sprintf( $disabled_template, 'prev', $label_icon . $this->get_settings( 'previous_label' ) );
		}

		$next_page = intval( $paged ) + 1;

		if ( $next_page <= $page_limit ) {
			$return['next'] = sprintf( $link_template, 'next', $this->get_wp_link_page( $next_page ), $this->get_settings( 'next_label' ) . $label_icon );
		} else {
			$return['next'] = sprintf( $disabled_template, 'next', $this->get_settings( 'next_label' ) . $label_icon );
		}

		return $return;
	}

	/**
	 * Normal Pagination
	 * 
	 * Includes the numbers pagination
	 * with or without arrows.
	 * 
	 * @since 1.0.0
	 */
	public function normal_pagination( $query = '' ) {
		$settings = $this->get_settings();

		if ( 'none' === $settings['pagination'] ) {
			return;
		}

		global $paged;

		$page_limit = $query->max_num_pages;
		
		if ( '' !== $settings['page_limit'] ) {
			$page_limit = min( $settings['page_limit'], $page_limit );
		}

		if ( 2 > $page_limit ) {
			return;
		}

		$total_pages = $query->max_num_pages;

		$has_numbers = in_array( $settings['pagination'], [ 'numbers', 'numbers-previous-next' ] );
		$has_prev_next = in_array( $settings['pagination'], [ 'previous-next', 'numbers-previous-next' ] );

		$links = [];

		if ( $has_numbers ) {
			$paginate_args = [
				'type' => 'array',
				'current' => $this->get_current_page(),
				'total' => $page_limit,
				'prev_next' => false,
				'show_all' => 'yes' !== $settings['shorten']
			];

			if ( is_singular() && ! is_front_page() ) {
				global $wp_rewrite;
				if ( $wp_rewrite->using_permalinks() ) {
					if ( ! is_multisite() ) {
						$base_url = trailingslashit( get_permalink() );
						$paginate_args['base'] = $base_url . 'page/%#%/'; // Add 'page/' to the base URL
						$paginate_args['format'] = user_trailingslashit( '%#%', 'single_paged' );
					}
				} else {
					$paginate_args['format'] = '?page=%#%';
				}
			}

			$links = paginate_links( $paginate_args );
		}

		if ( $has_prev_next ) {
			$prev_next = $this->get_posts_nav_link( $page_limit );
			array_unshift( $links, $prev_next['prev'] );
			$links[] = $prev_next['next'];
		}

		echo '<div class="m-okthemes-pagination" aria-label="'. esc_html__( 'Pagination', 'okthemes-toolkit' ) .'">'. implode( PHP_EOL, $links ) .'</div>';
	}

	/**
	 * Ajax Pagination
	 * 
	 * Load more Products via
	 * a button which request
	 * for ajax call and returns
	 * on the DOM.
	 * 
	 * @since 1.0.0
	 */
	protected function ajax_pagination() {
		if ( $this->get_settings( 'show_more_text' ) ) {
			$show_more = $this->get_settings( 'show_more_text' );
		} else {
			$show_more = __( 'Show More', 'okthemes-toolkit' );
		}

		$button_class = ['page-numbers', 'a-button'];
		if ( ! empty( $this->get_settings( 'pagination_hover_animation' ) ) ) {
			$button_class[] = 'elementor-animation-' . $this->get_settings('pagination_hover_animation');
		}

		$exclude = '';

		if ( isset( $this->query_args['post__not_in'] ) && ! empty( $this->query_args['post__not_in'] ) ) {
			$exclude = $this->query_args['post__not_in'];

			if ( ! empty ( $exclude ) ) {
				$exclude = implode( ', ', $exclude );
			}
		}

		$loading = $this->get_settings( 'show_more_loading_text' ) ? $this->get_settings( 'show_more_loading_text' ) : $show_more;

		echo '<div class="m-okthemes-pagination" aria-label="'. esc_html__( 'Pagination', 'okthemes-toolkit' ) .'"><button id="load-more-posts" class="'. implode(' ', $button_class) .'" data-text="'. $show_more .'" data-exclude="'. $exclude . '" data-loading="'. $loading .'">'. $show_more .'</button></div>';
	}

	/**
	 * Pagination
	 * 
	 * Displays a different pagination
	 * type which can make user able
	 * to navigate through pages or load
	 * more posts via show more button.
	 * 
	 * @since 1.0.0
	 */
	protected function get_pagination( $query ) {
		if ( $this->get_settings( 'pagination' ) == 'none' || $this->get_settings( 'carousel' ) == 'yes' ) {
			return;
		}

		if ( $this->get_settings( 'pagination' ) == 'show-more' && $query->max_num_pages > $this->get_paged() ) {
			$html = $this->ajax_pagination();
		} else {
			$html = $this->normal_pagination( $query );
		}

		return '<div class="m-okthemes-pagination" aria-label="'. esc_html__( 'Pagination', 'okthemes-toolkit' ) .'">' . $html . '</div>';
	}

	/**
	 * Prepare Term
	 * 
	 * Accepts the term and returns
	 * with the correct taxonomy;
	 * 
	 * @since 1.0.0
	 */
	protected function prepare_term( $term ) {
		$term = $term[0];

		// Taxonomy
		switch ( $term->taxonomy ) {
			case 'post_tag':
				$term->taxonomy = 'tag';
				break;
		}

		return $term;
	}

	/**
	 * Repeater Item
	 * 
	 * Add Repeater Item when metro or
	 * carousel is activated.
	 * 
	 * @since 1.0.0
	 */
	protected function repeater_item( $post_class ) {
		if ( $this->get_settings( 'layout' ) != 'metro' && $this->get_settings( 'carousel' ) != 'yes' ) {
			return;
		}

		if ( $this->get_settings('product_metro') ) {
			foreach ( $this->get_settings('product_metro') as $metro ) {
				if ( $metro['id'] == get_the_ID() ) {
					return $post_class = ' elementor-repeater-item-' . $metro['_id'];
				}
			}
		}
	}

	/**
	 * Filters
	 * 
	 * Display sortable filters which
	 * are able to sort different posts
	 * due a certain taxonomy,
	 * 
	 * @since 1.0.0
	 */
	protected function get_filters( $query ) {
		if ( $this->get_settings( 'filters' ) != 'yes' || $this->get_settings( 'carousel' ) == 'yes' ) {
			return;
		}

		// Query
		$query = $this->get_query( true );

		// Filters in Manual Selection
		$filters_tax = $this->get_settings( 'filters_tax' );

		// Save Terms for Filters
		if ( $query->have_posts() ) {
			while ( $query->have_posts() ) {
				$query->the_post();

				if ( get_the_terms( get_the_ID(), $filters_tax ) ) {
					foreach ( get_the_terms( get_the_ID(), $filters_tax ) as $post_term ) {
						if ( ! in_array( $post_term, $this->terms ) ) {
							$this->terms[] = $post_term;
						}
					}
				}
			}
		}

		if ( ! empty( $this->terms ) ) {
		?>
		<div class="m-okthemes-filters" aria-label="<?php echo esc_html__( 'Filters', 'okthemes-toolkit' ) ?>">
			<ul <?php echo $this->get_render_attribute_string( 'filters' ) ?>>
				<?php if ( $this->get_settings( 'filter_all' ) == 'yes' ) : ?>
					<li class="m-okthemes-filters__item active" data-filter="*"><?php echo $this->get_settings( 'filter_all_string' ) ? $this->get_settings( 'filter_all_string' ) : esc_html__( 'All', 'okthemes-toolkit' ) ?></li>
				<?php endif; ?>

				<?php foreach( $this->terms as $term ) : ?>
					<li class="m-okthemes-filters__item" data-filter="<?php echo esc_attr( $term->taxonomy ) ?>-<?php echo esc_attr( $term->slug ) ?>"><?php echo esc_attr( $term->name ) ?></li>
				<?php endforeach; ?>
			</ul>
		</div>
		<?php
		}
	}

	/**
	 * Packery
	 * 
	 * Loads Packery in 
	 * Masonry & Metro.
	 * 
	 * @since 1.0.0
	 */
	protected function load_packery() {
		$isMetroMasonry = ( $this->get_settings( 'layout' ) == 'masonry' || $this->get_settings( 'layout' ) == 'metro' );

		if ( \Elementor\Plugin::$instance->editor->is_edit_mode() == true && $isMetroMasonry ) {
		?>
		<script>
			var grid = new Packery('.e-con.e-grid[data-masonry-id="<?php echo esc_attr(md5($this->get_id())); ?>"]', {
        		itemSelector: '.e-grid-item'
    		});

			window.document.onload = function () {
				grid.layout();
			}	
		</script>
		<?php
		}
	}

	protected function render() {
		$settings = $this->get_settings_for_display();
	
		$query = $this->get_query();
	
		$this->get_filters($query);
	
		// Carousel Class
		$carousel_dots = (in_array($settings['navigation'], ['dots', 'arrows-dots']));
		$carousel_arrows = (in_array($settings['navigation'], ['arrows', 'arrows-dots']));
	
		// Set up the container class with new Elementor grid classes
		$container_classes = [];

		if ($settings['carousel'] == 'yes') {
			$container_classes[] = 'okthemes-swiper';
		} else {
			// New Elementor grid container
			$container_classes[] = 'products';
					
			// Set CSS variables for grid
			$columns = !empty($settings['columns']) ? $settings['columns'] : '3';
			$container_classes[] = 'columns-'.$columns;


			// Add grid data attributes for the container
			$this->add_render_attribute('container', 'class', $container_classes);
			
			// Add masonry-id to the container
			$this->add_render_attribute('container', 'data-masonry-id', esc_attr(md5($this->get_id())));
		}

		// Grid 
		$this->add_render_attribute('grid', 'class', [
			$settings['carousel'] == 'yes' ? 'swiper-wrapper okthemes-slides' : 'e-con-inner',
		]);

		// Item classes
		if ($settings['carousel'] == 'yes') {
			$articleClass = 'swiper-slide';
		} else {
			$articleClass = 'e-grid-item'; // Updated class for grid items
		}
	
		// Animations
		if (!\Elementor\Plugin::$instance->editor->is_edit_mode() && isset($settings['animation']) && $settings['animation'] == 'yes' && isset($settings['ok_animations']) && $settings['ok_animations'] != '') {
			$articleClass .= ' h-okthemes-animation--wow';
		}
		?>
		<?php if ($settings['carousel'] == 'yes') : ?>
			<div class="okthemes-swiper">
				<div class="okthemes-slides-wrapper okthemes-main-swiper swiper-container" data-animation-id="<?php echo esc_attr(md5($this->get_id())); ?>">
					<div class="swiper-wrapper okthemes-slides">
		<?php else: ?>
			<ul <?php echo $this->get_render_attribute_string('container'); ?>>
		<?php endif; ?>

					<?php 
				if ($query->have_posts()) {
					if ($settings['carousel'] == 'yes') {
						woocommerce_product_loop_start(false);
						$add_slide_class = function( $classes ) {
							$classes[] = 'swiper-slide';
							return $classes;
						};
						add_filter( 'woocommerce_post_class', $add_slide_class );
					}

					while ($query->have_posts()) {
						$query->the_post();
						$post_class = '';

						if ($this->repeater_item($post_class)) {
							$post_class = $this->repeater_item($post_class);
						}
						?>
						<?php
							// Load the standard WooCommerce product template
							wc_get_template_part('content', 'product');
						?>
						<?php
					}

					if ($settings['carousel'] == 'yes') {
						remove_filter( 'woocommerce_post_class', $add_slide_class );
						woocommerce_product_loop_end(false);
					}

					woocommerce_reset_loop();
				}
				wp_reset_postdata();
				?>

			<?php if ($settings['carousel'] == 'yes') : ?>
				
				</div>
			</div>
	
			<?php if (isset($settings['dots_style']) && $settings['dots_style'] == 'scrollbar') : ?>
				<div class="swiper-scrollbar"></div>
			<?php endif; ?>
	
			<?php if ($carousel_dots) : ?>
				<div class="swiper-pagination okthemes-swiper-dots" data-swiper-pagination-id="<?php echo md5($this->get_id()) ?>"></div>
			<?php endif; ?>
			
			<?php if ($carousel_arrows) : ?>
				<div class="okthemes-swiper-button okthemes-swiper-button--prev">
					<?php if (isset($settings['arrows_icon'])) : ?>
						<div class="okthemes-icon"><?php Icons_Manager::render_icon($settings['arrows_icon'], ['aria-hidden' => 'true']); ?></div>
					<?php endif; ?>
					<span class="okthemes-swiper-button--hidden"><?php _e('Previous', 'okthemes-toolkit'); ?></span>
				</div>
				<div class="okthemes-swiper-button okthemes-swiper-button--next">
					<?php if (isset($settings['arrows_icon'])) : ?>
						<div class="okthemes-icon"><?php Icons_Manager::render_icon($settings['arrows_icon'], ['aria-hidden' => 'true']); ?></div>
					<?php endif; ?>
					<span class="okthemes-swiper-button--hidden"><?php _e('Next', 'okthemes-toolkit'); ?></span>
				</div>
			<?php endif; ?>

			</div>
		<?php else: ?>
			</ul>
		<?php endif; ?>
	
		<?php 
		$this->get_pagination($query);
		$this->load_packery();
	}

	protected function content_template() {}
}