<?php
/**
 * PowerPack WooCommerce Categories.
 *
 * @package PowerPack
 */

namespace PowerpackElements\Modules\Woocommerce\Widgets;

use PowerpackElements\Base\Powerpack_Widget;
use PowerpackElements\Classes\PP_Helper;

use Elementor\Controls_Manager;
use Elementor\Icons_Manager;
use Elementor\Group_Control_Typography;
use Elementor\Group_Control_Background;
use Elementor\Group_Control_Border;
use Elementor\Group_Control_Box_Shadow;
use Elementor\Group_Control_Image_Size;
use Elementor\Core\Kits\Documents\Tabs\Global_Typography;

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

/**
 * Woo - Categories Widget
 */
class Woo_Categories extends Powerpack_Widget {

	/**
	 * Number of categories rendered by the current carousel.
	 *
	 * Read by the screen reader status message, which announces the slide
	 * count and so cannot be built until the loop has run.
	 *
	 * @var int
	 * @access public
	 */
	public $total_slides = 0;

	/**
	 * Retrieve Woo - Categories widget categories.
	 *
	 * @access public
	 *
	 * @return array Widget categories.
	 */
	public function get_categories() {
		return parent::get_woo_categories();
	}

	/**
	 * Retrieve Woo - Categories widget name.
	 *
	 * @access public
	 *
	 * @return string Widget name.
	 */
	public function get_name() {
		return parent::get_widget_name( 'Woo_Categories' );
	}

	/**
	 * Retrieve Woo - Categories widget title.
	 *
	 * @access public
	 *
	 * @return string Widget title.
	 */
	public function get_title() {
		return parent::get_widget_title( 'Woo_Categories' );
	}

	/**
	 * Retrieve Woo - Categories widget icon.
	 *
	 * @access public
	 *
	 * @return string Widget icon.
	 */
	public function get_icon() {
		return parent::get_widget_icon( 'Woo_Categories' );
	}

	/**
	 * Get widget keywords.
	 *
	 * Retrieve the list of keywords the Woo - Categories widget belongs to.
	 *
	 * @since 1.4.11.0
	 * @access public
	 *
	 * @return array Widget keywords.
	 */
	public function get_keywords() {
		return parent::get_widget_keywords( 'Woo_Categories' );
	}

	/**
	 * Retrieve the list of scripts the Woo - Categories widget depended on.
	 *
	 * Used to set scripts dependencies required to run the widget.
	 *
	 * @access public
	 *
	 * @return array Widget scripts dependencies.
	 */
	public function get_script_depends() {
		if ( PP_Helper::is_edit_mode() || PP_Helper::is_preview_mode() ) {
			return [
				'swiper',
				'pp-carousel',
			];
		}

		$settings = $this->get_settings_for_display();
		$scripts = [];

		if ( 'carousel' === $settings['layout'] ) {
			array_push( $scripts, 'swiper', 'pp-carousel' );
		}

		return $scripts;
	}

	/**
	 * Retrieve the list of styles the Woo - Categories depended on.
	 *
	 * Used to set style dependencies required to run the widget.
	 *
	 * @access public
	 *
	 * @return array Widget styles dependencies.
	 */
	public function get_style_depends() {
		if ( PP_Helper::is_edit_mode() || PP_Helper::is_preview_mode() ) {
			return [ 'e-swiper', 'pp-swiper', 'pp-woocommerce' ];
		}

		$settings = $this->get_settings_for_display();
		$styles   = [ 'pp-woocommerce' ];

		if ( 'carousel' === $settings['layout'] ) {
			array_push( $styles, 'e-swiper', 'pp-swiper' );
		}

		return $styles;
	}

	/**
	 * Whether Elementor should wrap the widget in its own container.
	 *
	 * The widget renders its own wrapper, so the extra one is dropped whenever
	 * optimized markup is switched on.
	 *
	 * @access public
	 *
	 * @return bool
	 */
	public function has_widget_inner_wrapper(): bool {
		return ! PP_Helper::is_feature_active( 'e_optimized_markup' );
	}

	/**
	 * Register Woo - Categories widget controls.
	 *
	 * Adds different input fields to allow the user to change and customize the widget settings.
	 *
	 * @since 2.0.3
	 * @access protected
	 */
	protected function register_controls() {
		/* Product Control */
		$this->register_content_general_controls();
		$this->register_content_grid_controls();
		$this->register_content_carousel_controls();
		$this->register_content_filter_controls();

		/* Style */
		$this->register_style_layout_controls();
		$this->register_style_category_controls();
		/* Style Tab: Arrows */
		$this->register_style_arrows_controls();
		/* Style Tab: Dots */
		$this->register_style_dots_controls();
	}

	/**
	 * Register toggle widget controls.
	 *
	 * Adds different input fields to allow the user to change and customize the widget settings.
	 *
	 * @access protected
	 */
	protected function register_content_general_controls() {

		$this->start_controls_section(
			'section_layout',
			[
				'label'                 => esc_html__( 'Layout', 'powerpack' ),
				'tab'                   => Controls_Manager::TAB_CONTENT,
			]
		);

		$this->add_control(
			'layout',
			[
				'label'                 => esc_html__( 'Layout', 'powerpack' ),
				'type'                  => Controls_Manager::SELECT,
				'default'               => 'grid',
				'options'               => [
					'grid'      => esc_html__( 'Grid', 'powerpack' ),
					'carousel'  => esc_html__( 'Carousel', 'powerpack' ),
					'tiles'     => esc_html__( 'Tiles', 'powerpack' ),
				],
			]
		);

		$this->add_control(
			'tiles_style',
			[
				'label'                 => esc_html__( 'Tiles Style', 'powerpack' ),
				'type'                  => Controls_Manager::SELECT,
				'default'               => '1',
				'options'               => [
					'1'     => esc_html__( 'Style 1', 'powerpack' ),
					'2'     => esc_html__( 'Style 2', 'powerpack' ),
				],
				'condition'             => [
					'layout'    => 'tiles',
				],
			]
		);

		$this->add_control(
			'cats_count',
			[
				'label'                 => esc_html__( 'Categories Count', 'powerpack' ),
				'type'                  => Controls_Manager::NUMBER,
				'default'               => '4',
			]
		);

		$this->add_control(
			'content_position',
			[
				'label'                 => esc_html__( 'Content Position', 'powerpack' ),
				'type'                  => Controls_Manager::SELECT,
				'default'               => 'overlay',
				'options'               => [
					'default'   => esc_html__( 'Below Image', 'powerpack' ),
					'overlay'   => esc_html__( 'Over Image', 'powerpack' ),
				],
				'condition'             => [
					'layout!'   => 'tiles',
				],
			]
		);

		$this->add_group_control(
			Group_Control_Image_Size::get_type(),
			[
				'name'    => 'image_size',
				'label'   => esc_html__( 'Image Size', 'powerpack' ),
				'default' => 'woocommerce_thumbnail',
			]
		);

		$this->add_control(
			'cat_title',
			[
				'label'                 => esc_html__( 'Category Title', 'powerpack' ),
				'type'                  => Controls_Manager::SWITCHER,
				'default'               => 'yes',
				'label_on'              => esc_html__( 'Show', 'powerpack' ),
				'label_off'             => esc_html__( 'Hide', 'powerpack' ),
				'return_value'          => 'yes',
			]
		);

		$this->add_control(
			'cat_title_html_tag',
			[
				'label'                 => esc_html__( 'Title HTML Tag', 'powerpack' ),
				'type'                  => Controls_Manager::SELECT,
				// h2 is what the widget hardcoded before this control existed.
				'default'               => 'h2',
				'options'               => [
					'h1'   => esc_html__( 'H1', 'powerpack' ),
					'h2'   => esc_html__( 'H2', 'powerpack' ),
					'h3'   => esc_html__( 'H3', 'powerpack' ),
					'h4'   => esc_html__( 'H4', 'powerpack' ),
					'h5'   => esc_html__( 'H5', 'powerpack' ),
					'h6'   => esc_html__( 'H6', 'powerpack' ),
					'div'  => esc_html__( 'div', 'powerpack' ),
					'span' => esc_html__( 'span', 'powerpack' ),
					'p'    => esc_html__( 'p', 'powerpack' ),
				],
				'condition'             => [
					'cat_title' => 'yes',
				],
			]
		);

		$this->add_control(
			'product_count',
			[
				'label'                 => esc_html__( 'Product Count', 'powerpack' ),
				'type'                  => Controls_Manager::SWITCHER,
				'default'               => 'yes',
				'label_on'              => esc_html__( 'Show', 'powerpack' ),
				'label_off'             => esc_html__( 'Hide', 'powerpack' ),
				'return_value'          => 'yes',
			]
		);

		$this->add_control(
			'cat_desc',
			[
				'label'                 => esc_html__( 'Category Description', 'powerpack' ),
				'type'                  => Controls_Manager::SWITCHER,
				'default'               => '',
				'label_on'              => esc_html__( 'Show', 'powerpack' ),
				'label_off'             => esc_html__( 'Hide', 'powerpack' ),
				'return_value'          => 'yes',
			]
		);

		$this->add_control(
			'category_desc_limit',
			[
				'label'                 => esc_html__( 'Words Limit', 'powerpack' ),
				'type'                  => Controls_Manager::TEXT,
				'default'               => '',
				'ai'                    => [
					'active' => false,
				],
				'condition'             => [
					'cat_desc' => 'yes',
				],
			]
		);

		$this->end_controls_section();
	}

	/**
	 * Register Grid Controls.
	 *
	 * @access protected
	 */
	protected function register_content_grid_controls() {

		$this->start_controls_section(
			'section_grid_settings',
			[
				'label'                 => esc_html__( 'Grid Options', 'powerpack' ),
				'tab'                   => Controls_Manager::TAB_CONTENT,
				'condition'             => [
					'layout!' => 'carousel',
				],
			]
		);

		$this->add_responsive_control(
			'columns',
			[
				'label'                 => esc_html__( 'Columns', 'powerpack' ),
				'type'                  => Controls_Manager::SELECT,
				'default'               => '3',
				'tablet_default'        => '2',
				'mobile_default'        => '1',
				'options'               => [
					'1' => '1',
					'2' => '2',
					'3' => '3',
					'4' => '4',
					'5' => '5',
					'6' => '6',
					'7' => '7',
					'8' => '8',
				],
				'prefix_class'          => 'elementor-grid%s-',
				'frontend_available'    => true,
			]
		);

		$this->end_controls_section();
	}

	/**
	 * Register Carousel Controls.
	 *
	 * @access protected
	 */
	protected function register_content_carousel_controls() {
		$this->start_controls_section(
			'section_carousel_options',
			[
				'label'                 => esc_html__( 'Carousel Options', 'powerpack' ),
				'type'                  => Controls_Manager::SECTION,
				'condition'             => [
					'layout'   => 'carousel',
				],
			]
		);

		$this->add_responsive_control(
			'slides_to_show',
			[
				'label'                 => esc_html__( 'Categories to Show', 'powerpack' ),
				'type'                  => Controls_Manager::NUMBER,
				'default'               => 4,
				'tablet_default'        => 3,
				'mobile_default'        => 1,
			]
		);

		$this->add_responsive_control(
			'slides_to_scroll',
			[
				'label'                 => esc_html__( 'Categories to Scroll', 'powerpack' ),
				'type'                  => Controls_Manager::NUMBER,
				'default'               => 1,
				'tablet_default'        => 1,
				'mobile_default'        => 1,
			]
		);

		$this->add_control(
			'autoplay',
			[
				'label'                 => esc_html__( 'Autoplay', 'powerpack' ),
				'type'                  => Controls_Manager::SWITCHER,
				'return_value'          => 'yes',
				'default'               => '',
			]
		);
		$this->add_control(
			'autoplay_speed',
			[
				'label'                 => esc_html__( 'Autoplay Speed', 'powerpack' ),
				'type'                  => Controls_Manager::NUMBER,
				'default'               => 3000,
				'condition'             => [
					'autoplay' => 'yes',
				],
			]
		);
		$this->add_control(
			'pause_on_hover',
			[
				'label'                 => esc_html__( 'Pause on Hover', 'powerpack' ),
				'type'                  => Controls_Manager::SWITCHER,
				'return_value'          => 'yes',
				'default'               => 'yes',
				'frontend_available'    => true,
				'condition'             => [
					'autoplay' => 'yes',
				],
			]
		);

		$this->add_control(
			'infinite',
			[
				'label'                 => esc_html__( 'Infinite Loop', 'powerpack' ),
				'type'                  => Controls_Manager::SWITCHER,
				'return_value'          => 'yes',
				'default'               => 'yes',
			]
		);

		$this->add_control(
			'transition_speed',
			[
				'label'                 => esc_html__( 'Transition Speed (ms)', 'powerpack' ),
				'type'                  => Controls_Manager::NUMBER,
				'default'               => 600,
			]
		);

		$this->add_control(
			'navigation',
			[
				'label'                 => esc_html__( 'Navigation', 'powerpack' ),
				'type'                  => Controls_Manager::HEADING,
				'separator'             => 'before',
			]
		);

		$this->add_control(
			'arrows',
			[
				'label'                 => esc_html__( 'Arrows', 'powerpack' ),
				'type'                  => Controls_Manager::SWITCHER,
				'return_value'          => 'yes',
				'default'               => 'yes',
			]
		);

		$this->add_control(
			'dots',
			[
				'label'                 => esc_html__( 'Dots', 'powerpack' ),
				'type'                  => Controls_Manager::SWITCHER,
				'return_value'          => 'yes',
				'default'               => 'yes',
			]
		);

		$this->end_controls_section();
	}

	/**
	 * Register Woo Products Filter Controls.
	 *
	 * @access protected
	 */
	protected function register_content_filter_controls() {

		$this->start_controls_section(
			'section_filter_field',
			[
				'label'                 => esc_html__( 'Filters', 'powerpack' ),
				'tab'                   => Controls_Manager::TAB_CONTENT,
			]
		);

			$this->add_control(
				'category_filter_rule',
				[
					'label'   => esc_html__( 'Category Filter Rule', 'powerpack' ),
					'type'    => Controls_Manager::SELECT,
					'default' => 'all',
					'options' => [
						'all'     => esc_html__( 'Show All', 'powerpack' ),
						'top'     => esc_html__( 'Only Top Level', 'powerpack' ),
						'include' => esc_html__( 'Match These Categories', 'powerpack' ),
						'exclude' => esc_html__( 'Exclude These Categories', 'powerpack' ),
					],
				]
			);
			$this->add_control(
				'category_filter',
				[
					'label'         => esc_html__( 'Categories', 'powerpack' ),
					'type'          => 'pp-query',
					'post_type'     => '',
					'options'       => [],
					'label_block'   => true,
					'multiple'      => true,
					'query_type'    => 'terms',
					'object_type'   => 'product_cat',
					'include_type'  => true,
					'condition'     => [
						'category_filter_rule' => [ 'include', 'exclude' ],
					],
				]
			);
			$this->add_control(
				'display_empty_cat',
				[
					'label'                 => esc_html__( 'Display Empty Categories', 'powerpack' ),
					'type'                  => Controls_Manager::SWITCHER,
					'default'               => '',
					'label_on'              => esc_html__( 'Yes', 'powerpack' ),
					'label_off'             => esc_html__( 'No', 'powerpack' ),
					'return_value'          => 'yes',
				]
			);
			$this->add_control(
				'orderby',
				[
					'label'   => esc_html__( 'Order by', 'powerpack' ),
					'type'    => Controls_Manager::SELECT,
					'default' => 'name',
					'options' => [
						'name'  => esc_html__( 'Name', 'powerpack' ),
						'slug'  => esc_html__( 'Slug', 'powerpack' ),
						'desc'  => esc_html__( 'Description', 'powerpack' ),
						'count' => esc_html__( 'Count', 'powerpack' ),
						'menu_order' => esc_html__( 'Menu Order', 'powerpack' ),
					],
				]
			);

			$this->add_control(
				'order',
				[
					'label'   => esc_html__( 'Order', 'powerpack' ),
					'type'    => Controls_Manager::SELECT,
					'default' => 'desc',
					'options' => [
						'desc' => esc_html__( 'Descending', 'powerpack' ),
						'asc'  => esc_html__( 'Ascending', 'powerpack' ),
					],
				]
			);
		$this->end_controls_section();
	}

	/**
	 * Style Tab
	 */
	/**
	 * Register Layout Controls.
	 *
	 * @since 1.3.3
	 * @access protected
	 */
	protected function register_style_layout_controls() {
		$this->start_controls_section(
			'section_design_layout',
			[
				'label'                 => esc_html__( 'Layout', 'powerpack' ),
				'tab'                   => Controls_Manager::TAB_STYLE,
			]
		);

		$this->add_responsive_control(
			'column_gap',
			[
				'label'                 => esc_html__( 'Columns Gap', 'powerpack' ),
				'type'                  => Controls_Manager::SLIDER,
				'size_units'            => [ 'px', 'em', 'rem', 'custom' ],
				'default'               => [
					'size' => 20,
				],
				'range'                => [
					'px' => [
						'min' => 0,
						'max' => 100,
					],
				],
				'render_type'           => 'template',
				'selectors'             => [
					'{{WRAPPER}}' => '--grid-column-gap: {{SIZE}}{{UNIT}};',
				],
			]
		);

		$this->add_responsive_control(
			'row_gap',
			[
				'label'                 => esc_html__( 'Rows Gap', 'powerpack' ),
				'type'                  => Controls_Manager::SLIDER,
				'size_units'            => [ 'px', 'em', 'rem', 'custom' ],
				'default'               => [
					'size' => 35,
				],
				'range'                => [
					'px' => [
						'min' => 0,
						'max' => 100,
					],
				],
				'selectors'             => [
					'{{WRAPPER}}' => '--grid-row-gap: {{SIZE}}{{UNIT}};',
					'{{WRAPPER}} .pp-woo-categories-tiles .product' => 'margin-bottom: {{SIZE}}{{UNIT}};',
					'{{WRAPPER}} .pp-woo-cat-tiles-1 .pp-woo-cat-tiles-center .product, {{WRAPPER}} .pp-woo-cat-tiles-2 .pp-woo-cat-tiles-right .product' => 'height: calc((550px - {{SIZE}}{{UNIT}}) / 2);',
				],
				'condition'             => [
					'layout' => [ 'grid', 'tiles' ],
				],
			]
		);

		$this->add_group_control(
			Group_Control_Border::get_type(),
			[
				'name'                  => 'column_border',
				'label'                 => esc_html__( 'Border', 'powerpack' ),
				'placeholder'           => '1px',
				'default'               => '1px',
				'separator'             => 'before',
				'selector'              => '{{WRAPPER}} .pp-woo-categories .product-category .pp-grid-item',
			]
		);

			$this->add_control(
				'column_border_color_hover',
				[
					'label'                 => esc_html__( 'Border Hover Color', 'powerpack' ),
					'type'                  => Controls_Manager::COLOR,
					'selectors'             => [
						'{{WRAPPER}} .pp-woo-categories .product-category .pp-grid-item:hover' => 'border-color: {{VALUE}};',
					],
				]
			);

		$this->add_group_control(
			Group_Control_Box_Shadow::get_type(),
			[
				'name'     => 'column_box_shadow',
				'separator' => 'before',
				'selector'  => '{{WRAPPER}} .pp-woo-categories .product-category .pp-grid-item',
			]
		);

		$this->end_controls_section();
	}

	/**
	 * Register Category Content Controls.
	 *
	 * @since 1.3.3
	 * @access protected
	 */
	protected function register_style_category_controls() {
		$this->start_controls_section(
			'section_design_cat_content',
			[
				'label'                 => esc_html__( 'Category Content', 'powerpack' ),
				'tab'                   => Controls_Manager::TAB_STYLE,
			]
		);

		$this->add_control(
			'cat_content_vertical_align',
			[
				'label'                 => esc_html__( 'Vertical Align', 'powerpack' ),
				'type'                  => Controls_Manager::CHOOSE,
				'label_block'           => false,
				'default'               => 'middle',
				'options'               => [
					'top'          => [
						'title'    => esc_html__( 'Top', 'powerpack' ),
						'icon'     => 'eicon-v-align-top',
					],
					'middle'       => [
						'title'    => esc_html__( 'Center', 'powerpack' ),
						'icon'     => 'eicon-v-align-middle',
					],
					'bottom'       => [
						'title'    => esc_html__( 'Bottom', 'powerpack' ),
						'icon'     => 'eicon-v-align-bottom',
					],
				],
				'selectors'             => [
					'{{WRAPPER}} .pp-woo-categories-overlay .product .pp-product-cat-content-wrap'   => 'justify-content: {{VALUE}};',
				],
				'selectors_dictionary'  => [
					'top'          => 'flex-start',
					'middle'       => 'center',
					'bottom'       => 'flex-end',
				],
				'conditions' => [
					'relation' => 'or',
					'terms' => [
						[
							'relation' => 'and',
							'terms' => [
								[
									'relation' => 'or',
									'terms' => [
										[
											'name' => 'layout',
											'operator' => '==',
											'value' => 'grid',
										],
										[
											'name' => 'layout',
											'operator' => '==',
											'value' => 'carousel',
										],
									],
								],
								[
									'name' => 'content_position',
									'operator' => '==',
									'value' => 'overlay',
								],
							],
						],
						[
							'name' => 'layout',
							'operator' => '==',
							'value' => 'tiles',
						],
					],
				],
			]
		);

		$this->add_control(
			'cat_content_horizontal_align',
			[
				'label'                 => esc_html__( 'Horizontal Align', 'powerpack' ),
				'type'                  => Controls_Manager::CHOOSE,
				'label_block'           => false,
				'options'               => [
					'left'      => [
						'title' => esc_html__( 'Left', 'powerpack' ),
						'icon'  => 'eicon-h-align-left',
					],
					'center'           => [
						'title' => esc_html__( 'Center', 'powerpack' ),
						'icon'  => 'eicon-h-align-center',
					],
					'right'            => [
						'title' => esc_html__( 'Right', 'powerpack' ),
						'icon'  => 'eicon-h-align-right',
					],
					'justify'   => [
						'title'    => esc_html__( 'Stretch', 'powerpack' ),
						'icon'     => 'eicon-h-align-stretch',
					],
				],
				'default'               => 'center',
				'selectors_dictionary'  => [
					'left'     => 'flex-start',
					'center'   => 'center',
					'right'    => 'flex-end',
					'justify'  => 'stretch',
				],
				'selectors'             => [
					'{{WRAPPER}} .pp-woo-categories-overlay .product .pp-product-cat-content-wrap' => 'align-items: {{VALUE}};',
				],
				'conditions' => [
					'relation' => 'or',
					'terms' => [
						[
							'relation' => 'and',
							'terms' => [
								[
									'relation' => 'or',
									'terms' => [
										[
											'name' => 'layout',
											'operator' => '==',
											'value' => 'grid',
										],
										[
											'name' => 'layout',
											'operator' => '==',
											'value' => 'carousel',
										],
									],
								],
								[
									'name' => 'content_position',
									'operator' => '==',
									'value' => 'overlay',
								],
							],
						],
						[
							'name' => 'layout',
							'operator' => '==',
							'value' => 'tiles',
						],
					],
				],
			]
		);
			$this->add_control(
				'cat_content_text_align',
				[
					'label'                 => esc_html__( 'Text Alignment', 'powerpack' ),
					'type'                  => Controls_Manager::CHOOSE,
					'label_block'  => false,
					'options'      => [
						'left'   => [
							'title' => esc_html__( 'Left', 'powerpack' ),
							'icon'  => 'eicon-text-align-left',
						],
						'center' => [
							'title' => esc_html__( 'Center', 'powerpack' ),
							'icon'  => 'eicon-text-align-center',
						],
						'right'  => [
							'title' => esc_html__( 'Right', 'powerpack' ),
							'icon'  => 'eicon-text-align-right',
						],
					],
					'default'               => 'center',
					'selectors'             => [
						'{{WRAPPER}} .pp-woo-categories .product .pp-product-cat-content' => 'text-align: {{VALUE}};',
					],
					'separator'             => 'after',
				]
			);

			$this->start_controls_tabs( 'cat_content_tabs_style' );

			$this->start_controls_tab(
				'cat_content_normal',
				[
					'label'                 => esc_html__( 'Normal', 'powerpack' ),
				]
			);

			$this->add_group_control(
				Group_Control_Background::get_type(),
				[
					'name'                  => 'cat_content_background',
					'types'                 => [ 'classic', 'gradient' ],
					'selector'              => '{{WRAPPER}} .pp-woo-categories .product .pp-product-cat-content',
				]
			);

			$this->add_control(
				'cat_content_margin',
				[
					'label'                 => esc_html__( 'Margin', 'powerpack' ),
					'type'                  => Controls_Manager::DIMENSIONS,
					'size_units'            => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
					'selectors'             => [
						'{{WRAPPER}} .pp-woo-categories .product .pp-product-cat-content' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
					],
					'separator'             => 'before',
				]
			);

			$this->add_control(
				'cat_content_padding',
				[
					'label'                 => esc_html__( 'Padding', 'powerpack' ),
					'type'                  => Controls_Manager::DIMENSIONS,
					'size_units'            => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
					'default'               => [
						'top'      => '10',
						'right'    => '10',
						'bottom'   => '10',
						'left'     => '10',
						'isLinked' => true,
					],
					'selectors'             => [
						'{{WRAPPER}} .pp-woo-categories .product .pp-product-cat-content' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
					],
				]
			);

			$this->add_control(
				'cat_content_title_heading',
				[
					'label'                 => esc_html__( 'Title', 'powerpack' ),
					'type'                  => Controls_Manager::HEADING,
					'separator'             => 'before',
					'condition'             => [
						'cat_title' => 'yes',
					],
				]
			);

			$this->add_control(
				'cat_title_color',
				[
					'label'                 => esc_html__( 'Color', 'powerpack' ),
					'type'                  => Controls_Manager::COLOR,
					'selectors'             => [
						'{{WRAPPER}} .pp-woo-categories .product .woocommerce-loop-category__title' => 'color: {{VALUE}};',
					],
					'condition'             => [
						'cat_title' => 'yes',
					],
				]
			);

			$this->add_group_control(
				Group_Control_Typography::get_type(),
				[
					'name'                 => 'cat_content_title_typography',
					'label'                => esc_html__( 'Typography', 'powerpack' ),
					'global'                => [
						'default' => Global_Typography::TYPOGRAPHY_PRIMARY,
					],
					'selector'             => '{{WRAPPER}} .pp-woo-categories .product .woocommerce-loop-category__title',
					'condition'            => [
						'cat_title' => 'yes',
					],
				]
			);

			$this->add_control(
				'cat_content_count_heading',
				[
					'label'                 => esc_html__( 'Product Count', 'powerpack' ),
					'type'                  => Controls_Manager::HEADING,
					'separator'             => 'before',
					'condition'             => [
						'product_count' => 'yes',
					],
				]
			);

			$this->add_control(
				'cat_count_color',
				[
					'label'                 => esc_html__( 'Color', 'powerpack' ),
					'type'                  => Controls_Manager::COLOR,
					'selectors'             => [
						'{{WRAPPER}} .pp-woo-categories .product .pp-product-cat-content .pp-count' => 'color: {{VALUE}};',
					],
					'condition'             => [
						'product_count' => 'yes',
					],
				]
			);

			$this->add_group_control(
				Group_Control_Typography::get_type(),
				[
					'name'                 => 'cat_content_count_typography',
					'label'                => esc_html__( 'Typography', 'powerpack' ),
					'global'                => [
						'default' => Global_Typography::TYPOGRAPHY_ACCENT,
					],
					'selector'             => '{{WRAPPER}} .pp-woo-categories .product .pp-product-cat-content .pp-count',
					'condition'            => [
						'product_count' => 'yes',
					],
				]
			);

			$this->add_control(
				'cat_desc_heading',
				[
					'label'                 => esc_html__( 'Category Description', 'powerpack' ),
					'type'                  => Controls_Manager::HEADING,
					'separator'             => 'before',
					'condition'             => [
						'cat_desc'  => 'yes',
					],
				]
			);

			$this->add_control(
				'cat_desc_color',
				[
					'label'                 => esc_html__( 'Color', 'powerpack' ),
					'type'                  => Controls_Manager::COLOR,
					'selectors'             => [
						'{{WRAPPER}} .pp-woo-categories .product .pp-product-cat-content .pp-product-cat-desc' => 'color: {{VALUE}};',
					],
					'condition'             => [
						'cat_desc'  => 'yes',
					],
				]
			);

			$this->add_group_control(
				Group_Control_Typography::get_type(),
				[
					'name'                 => 'cat_desc_typography',
					'label'                => esc_html__( 'Typography', 'powerpack' ),
					'selector'             => '{{WRAPPER}} .pp-woo-categories .product .pp-product-cat-content .pp-product-cat-desc',
					'condition'             => [
						'cat_desc'  => 'yes',
					],
				]
			);

			$this->add_control(
				'cat_content_opacity',
				[
					'label'                 => esc_html__( 'Opacity', 'powerpack' ),
					'type'                  => Controls_Manager::SLIDER,
					'default'               => [
						'size' => 1,
					],
					'range'                 => [
						'px' => [
							'min'   => 0,
							'max'   => 1,
							'step'  => 0.01,
						],
					],
					'selectors'             => [
						'{{WRAPPER}} .pp-woo-categories .product .pp-product-cat-content' => 'opacity: {{SIZE}};',
					],
					'separator'             => 'before',
					'condition'             => [
						'content_position' => 'overlay',
					],
				]
			);

			$this->end_controls_tab();

			$this->start_controls_tab(
				'cat_content_hover',
				[
					'label'                 => esc_html__( 'Hover', 'powerpack' ),
				]
			);

			$this->add_group_control(
				Group_Control_Background::get_type(),
				[
					'name'                  => 'cat_content_background_hover',
					'types'                 => [ 'classic', 'gradient' ],
					'selector'              => '{{WRAPPER}} .pp-woo-categories .product-category .pp-grid-item:hover .pp-product-cat-content',
					'separator'             => 'after',
				]
			);

			$this->add_control(
				'cat_content_hover_title_color',
				[
					'label'                 => esc_html__( 'Title Color', 'powerpack' ),
					'type'                  => Controls_Manager::COLOR,
					'selectors'             => [
						'{{WRAPPER}} .pp-woo-categories .product-category .pp-grid-item:hover .woocommerce-loop-category__title' => 'color: {{VALUE}};',
					],
					'condition'             => [
						'cat_title' => 'yes',
					],
				]
			);

			$this->add_control(
				'cat_content_hover_count_color',
				[
					'label'                 => esc_html__( 'Product Count Color', 'powerpack' ),
					'type'                  => Controls_Manager::COLOR,
					'selectors'             => [
						'{{WRAPPER}} .pp-woo-categories .product-category .pp-grid-item:hover .pp-product-cat-content .pp-count' => 'color: {{VALUE}};',
					],
					'condition'             => [
						'product_count' => 'yes',
					],
				]
			);

			$this->add_control(
				'cat_hover_desc_color',
				[
					'label'                 => esc_html__( 'Description Color', 'powerpack' ),
					'type'                  => Controls_Manager::COLOR,
					'selectors'             => [
						'{{WRAPPER}} .pp-woo-categories .product-category .pp-grid-item:hover .pp-product-cat-content .pp-product-cat-desc' => 'color: {{VALUE}};',
					],
					'condition'             => [
						'cat_desc'  => 'yes',
					],
				]
			);

			$this->add_control(
				'cat_content_opacity_hover',
				[
					'label'                 => esc_html__( 'Opacity', 'powerpack' ),
					'type'                  => Controls_Manager::SLIDER,
					'default'               => [
						'size' => 1,
					],
					'range'                 => [
						'px' => [
							'min'   => 0,
							'max'   => 1,
							'step'  => 0.01,
						],
					],
					'selectors'             => [
						'{{WRAPPER}} .pp-woo-categories .product .pp-grid-item:hover .pp-product-cat-content' => 'opacity: {{SIZE}};',
					],
					'separator'             => 'before',
					'condition'             => [
						'content_position' => 'overlay',
					],
				]
			);

			$this->end_controls_tab();

			$this->end_controls_tabs();

		$this->end_controls_section();
	}

	/**
	 * Register Arrows Controls.
	 *
	 * @access protected
	 */
	protected function register_style_arrows_controls() {
		$this->start_controls_section(
			'section_arrows_style',
			[
				'label'     => esc_html__( 'Arrows', 'powerpack' ),
				'tab'       => Controls_Manager::TAB_STYLE,
				'condition' => [
					'layout'   => 'carousel',
					'arrows'   => 'yes',
				],
			]
		);

		$this->add_control(
			'select_arrow',
			[
				'label'                  => esc_html__( 'Choose Arrow', 'powerpack' ),
				'type'                   => Controls_Manager::ICONS,
				'fa4compatibility'       => 'arrow',
				'label_block'            => false,
				'default'                => [
					'value'   => 'fas fa-angle-right',
					'library' => 'fa-solid',
				],
				'skin'                   => 'inline',
				'exclude_inline_options' => 'svg',
				'recommended'            => [
					'fa-regular' => [
						'arrow-alt-circle-right',
						'caret-square-right',
						'hand-point-right',
					],
					'fa-solid'   => [
						'angle-right',
						'angle-double-right',
						'chevron-right',
						'chevron-circle-right',
						'arrow-right',
						'long-arrow-alt-right',
						'caret-right',
						'caret-square-right',
						'arrow-circle-right',
						'arrow-alt-circle-right',
						'toggle-right',
						'hand-point-right',
					],
				],
			]
		);

		$this->add_responsive_control(
			'arrows_size',
			[
				'label'      => esc_html__( 'Arrows Size', 'powerpack' ),
				'type'       => Controls_Manager::SLIDER,
				'size_units' => [ 'px', 'em', 'rem', 'custom' ],
				'default'    => [ 'size' => '22' ],
				'range'      => [
					'px' => [
						'min'  => 15,
						'max'  => 100,
						'step' => 1,
					],
				],
				'selectors'  => [
					'{{WRAPPER}} .pp-slider-arrow' => 'font-size: {{SIZE}}{{UNIT}}; line-height: {{SIZE}}{{UNIT}};',
				],
			]
		);

		$this->add_responsive_control(
			'arrows_position',
			[
				'label'      => esc_html__( 'Align Arrows', 'powerpack' ),
				'type'       => Controls_Manager::SLIDER,
				'size_units' => [ 'px', 'em', 'rem', 'custom' ],
				'range'      => [
					'px' => [
						'min'  => -100,
						'max'  => 50,
						'step' => 1,
					],
				],
				// Logical properties, to match how pp-swiper.css offsets these
				// arrows by default, so the alignment flips in RTL.
				'selectors'  => [
					'{{WRAPPER}} .pp-arrow-next' => 'inset-inline-end: {{SIZE}}{{UNIT}};',
					'{{WRAPPER}} .pp-arrow-prev' => 'inset-inline-start: {{SIZE}}{{UNIT}};',
				],
			]
		);

		$this->start_controls_tabs( 'tabs_arrows_style' );

		$this->start_controls_tab(
			'tab_arrows_normal',
			[
				'label'     => esc_html__( 'Normal', 'powerpack' ),
			]
		);

		$this->add_control(
			'arrows_bg_color_normal',
			[
				'label'     => esc_html__( 'Background Color', 'powerpack' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '',
				'selectors' => [
					'{{WRAPPER}} .pp-slider-arrow' => 'background-color: {{VALUE}};',
				],
			]
		);

		$this->add_control(
			'arrows_color_normal',
			[
				'label'     => esc_html__( 'Color', 'powerpack' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '',
				'selectors' => [
					'{{WRAPPER}} .pp-slider-arrow' => 'color: {{VALUE}};',
				],
			]
		);

		$this->add_group_control(
			Group_Control_Border::get_type(),
			[
				'name'        => 'arrows_border_normal',
				'label'       => esc_html__( 'Border', 'powerpack' ),
				'placeholder' => '1px',
				'default'     => '1px',
				'selector'    => '{{WRAPPER}} .pp-slider-arrow',
			]
		);

		$this->add_responsive_control(
			'arrows_border_radius_normal',
			[
				'label'      => esc_html__( 'Border Radius', 'powerpack' ),
				'type'       => Controls_Manager::DIMENSIONS,
				'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
				'selectors'  => [
					'{{WRAPPER}} .pp-slider-arrow' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
				],
			]
		);

		$this->end_controls_tab();

		$this->start_controls_tab(
			'tab_arrows_hover',
			[
				'label'     => esc_html__( 'Hover', 'powerpack' ),
			]
		);

		$this->add_control(
			'arrows_bg_color_hover',
			[
				'label'     => esc_html__( 'Background Color', 'powerpack' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '',
				'selectors' => [
					'{{WRAPPER}} .pp-slider-arrow:hover' => 'background-color: {{VALUE}};',
				],
			]
		);

		$this->add_control(
			'arrows_color_hover',
			[
				'label'     => esc_html__( 'Color', 'powerpack' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '',
				'selectors' => [
					'{{WRAPPER}} .pp-slider-arrow:hover' => 'color: {{VALUE}};',
				],
			]
		);

		$this->add_control(
			'arrows_border_color_hover',
			[
				'label'     => esc_html__( 'Border Color', 'powerpack' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '',
				'selectors' => [
					'{{WRAPPER}} .pp-slider-arrow:hover' => 'border-color: {{VALUE}};',
				],
			]
		);

		$this->end_controls_tab();

		$this->end_controls_tabs();

		$this->add_responsive_control(
			'arrows_padding',
			[
				'label'      => esc_html__( 'Padding', 'powerpack' ),
				'type'       => Controls_Manager::DIMENSIONS,
				'size_units' => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
				'selectors'  => [
					'{{WRAPPER}} .pp-slider-arrow' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
				],
				'separator'  => 'before',
			]
		);

		$this->end_controls_section();
	}

	/**
	 * Register Dots Controls.
	 *
	 * @access protected
	 */
	protected function register_style_dots_controls() {
		$this->start_controls_section(
			'section_dots_style',
			[
				'label'     => esc_html__( 'Dots', 'powerpack' ),
				'tab'       => Controls_Manager::TAB_STYLE,
				'condition' => [
					'layout'    => 'carousel',
					'dots'      => 'yes',
				],
			]
		);

		$this->add_control(
			'dots_position',
			[
				'label'                 => esc_html__( 'Position', 'powerpack' ),
				'type'                  => Controls_Manager::SELECT,
				'options'               => [
					'inside'     => esc_html__( 'Inside', 'powerpack' ),
					'outside'    => esc_html__( 'Outside', 'powerpack' ),
				],
				'default'               => 'outside',
			]
		);

		$this->add_responsive_control(
			'dots_size',
			[
				'label'      => esc_html__( 'Size', 'powerpack' ),
				'type'       => Controls_Manager::SLIDER,
				'size_units' => [ 'px', 'em', 'rem', 'custom' ],
				'range'      => [
					'px' => [
						'min'  => 2,
						'max'  => 40,
						'step' => 1,
					],
				],
				'selectors'  => [
					'{{WRAPPER}} .swiper-container-wrap .swiper-pagination-bullet' => 'width: {{SIZE}}{{UNIT}}; height: {{SIZE}}{{UNIT}};',
				],
			]
		);

		$this->add_responsive_control(
			'dots_spacing',
			[
				'label'      => esc_html__( 'Spacing', 'powerpack' ),
				'type'       => Controls_Manager::SLIDER,
				'size_units' => [ 'px', 'em', 'rem', 'custom' ],
				'range'      => [
					'px' => [
						'min'  => 1,
						'max'  => 30,
						'step' => 1,
					],
				],
				'selectors'  => [
					'{{WRAPPER}} .swiper-container-wrap .swiper-pagination-bullet' => 'margin-left: {{SIZE}}{{UNIT}}; margin-right: {{SIZE}}{{UNIT}}',
				],
			]
		);

		$this->start_controls_tabs( 'tabs_dots_style' );

		$this->start_controls_tab(
			'tab_dots_normal',
			[
				'label'     => esc_html__( 'Normal', 'powerpack' ),
			]
		);

		$this->add_control(
			'dots_color_normal',
			[
				'label'     => esc_html__( 'Color', 'powerpack' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '',
				'selectors' => [
					'{{WRAPPER}} .swiper-container-wrap .swiper-pagination-bullet' => 'background: {{VALUE}};',
				],
			]
		);

		$this->add_group_control(
			Group_Control_Border::get_type(),
			[
				'name'        => 'dots_border_normal',
				'label'       => esc_html__( 'Border', 'powerpack' ),
				'placeholder' => '1px',
				'default'     => '1px',
				'selector'    => '{{WRAPPER}} .swiper-container-wrap .swiper-pagination-bullet',
			]
		);

		$this->add_responsive_control(
			'dots_border_radius_normal',
			[
				'label'      => esc_html__( 'Border Radius', 'powerpack' ),
				'type'       => Controls_Manager::DIMENSIONS,
				'size_units' => [ 'px', '%', 'em', 'rem', 'custom' ],
				'selectors'  => [
					'{{WRAPPER}} .swiper-container-wrap .swiper-pagination-bullet' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
				],
			]
		);

		$this->add_responsive_control(
			'dots_margin',
			[
				'label'              => esc_html__( 'Margin', 'powerpack' ),
				'type'               => Controls_Manager::DIMENSIONS,
				'size_units'         => [ 'px', '%', 'em', 'rem', 'vw', 'custom' ],
				'allowed_dimensions' => 'vertical',
				'placeholder'        => [
					'top'    => '',
					'right'  => 'auto',
					'bottom' => '',
					'left'   => 'auto',
				],
				'selectors'          => [
					'{{WRAPPER}} .swiper-container-wrap .swiper-pagination-bullets' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
				],
			]
		);

		$this->end_controls_tab();

		$this->start_controls_tab(
			'tab_dots_active',
			[
				'label'     => esc_html__( 'Active', 'powerpack' ),
			]
		);

		$this->add_control(
			'dots_color_active',
			[
				'label'     => esc_html__( 'Color', 'powerpack' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '',
				'selectors' => [
					'{{WRAPPER}} .swiper-container-wrap .swiper-pagination-bullet.swiper-pagination-bullet-active' => 'background: {{VALUE}};',
				],
			]
		);

		$this->add_control(
			'dots_border_color_active',
			[
				'label'     => esc_html__( 'Border Color', 'powerpack' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '',
				'selectors' => [
					'{{WRAPPER}} .swiper-container-wrap .swiper-pagination-bullet.swiper-pagination-bullet-active' => 'border-color: {{VALUE}};',
				],
			]
		);

		$this->end_controls_tab();

		$this->start_controls_tab(
			'tab_dots_hover',
			[
				'label'     => esc_html__( 'Hover', 'powerpack' ),
			]
		);

		$this->add_control(
			'dots_color_hover',
			[
				'label'     => esc_html__( 'Color', 'powerpack' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '',
				'selectors' => [
					'{{WRAPPER}} .swiper-container-wrap .swiper-pagination-bullet:hover' => 'background: {{VALUE}};',
				],
			]
		);

		$this->add_control(
			'dots_border_color_hover',
			[
				'label'     => esc_html__( 'Border Color', 'powerpack' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '',
				'selectors' => [
					'{{WRAPPER}} .swiper-container-wrap .swiper-pagination-bullet:hover' => 'border-color: {{VALUE}};',
				],
			]
		);

		$this->end_controls_tab();

		$this->end_controls_tabs();

		$this->end_controls_section();
	}

	/**
	 * List all product categories.
	 *
	 * @access public
	 *
	 * @return string Rendered category list markup.
	 */
	public function query_product_categories() {

		$settings    = $this->get_settings();
		$include_ids = [];
		$exclude_ids = [];

		$atts = [
			'limit'   => ( $settings['cats_count'] ) ? $settings['cats_count'] : '-1',
			'columns' => ( $settings['columns'] ) ? $settings['columns'] : '4',
			'parent'  => '',
		];

		if ( 'top' === $settings['category_filter_rule'] ) {
			$atts['parent'] = 0;
		} elseif ( 'include' === $settings['category_filter_rule'] && is_array( $settings['category_filter'] ) ) {
			$include_ids = array_filter( array_map( 'trim', $settings['category_filter'] ) );
		} elseif ( 'exclude' === $settings['category_filter_rule'] && is_array( $settings['category_filter'] ) ) {
			$exclude_ids = array_filter( array_map( 'trim', $settings['category_filter'] ) );
		}

		$hide_empty = ( 'yes' === $settings['display_empty_cat'] ) ? 0 : 1;

		// Get terms and workaround WP bug with parents/pad counts.
		$args = [
			'orderby'    => ( $settings['orderby'] ) ? $settings['orderby'] : 'name',
			'order'      => ( $settings['order'] ) ? $settings['order'] : 'ASC',
			'hide_empty' => $hide_empty,
			'pad_counts' => true,
			'child_of'   => $atts['parent'],
			'include'    => $include_ids,
			'exclude'    => $exclude_ids,
		];

		/**
		 * Filters the term query arguments used by the Woo - Categories widget.
		 *
		 * @since 2.2.7
		 *
		 * @param array $args     Arguments passed to `get_terms()`.
		 * @param array $settings Widget settings.
		 */
		$args = apply_filters( 'ppe_woo_categories_query_args', $args, $settings );

		$product_categories = get_terms( 'product_cat', $args );

		if ( '' !== $atts['parent'] ) {
			$product_categories = wp_list_filter(
				$product_categories, [
					'parent' => $atts['parent'],
				]
			);
		}

		if ( $hide_empty ) {
			foreach ( $product_categories as $key => $category ) {
				if ( 0 === $category->count ) {
					unset( $product_categories[ $key ] );
				}
			}
		}

		$atts['limit'] = intval( $atts['limit'] );

		if ( $atts['limit'] > 0 ) {
			$product_categories = array_slice( $product_categories, 0, $atts['limit'] );
		}

		$columns = absint( $atts['columns'] );

		wc_set_loop_prop( 'columns', $columns );

		/* Category Image */
		remove_action( 'woocommerce_before_subcategory_title', 'woocommerce_subcategory_thumbnail', 10 );
		add_action( 'woocommerce_before_subcategory_title', [ $this, 'woocommerce_category_thumbnail_size' ], 10 );

		/* Category Link */
		remove_action( 'woocommerce_before_subcategory', 'woocommerce_template_loop_category_link_open', 10 );
		add_action( 'woocommerce_before_subcategory', [ $this, 'template_loop_category_link_open' ], 10 );

		/* Content Wrapper */
		add_action( 'woocommerce_before_subcategory_title', [ $this, 'category_content_start' ], 15 );
		add_action( 'woocommerce_after_subcategory_title', [ $this, 'category_content_end' ], 8 );

		if ( 'yes' === $settings['cat_desc'] ) {
			add_action( 'woocommerce_shop_loop_subcategory_title', [ $this, 'category_description' ], 12 );
		}

		/* Category Title */
		remove_action( 'woocommerce_shop_loop_subcategory_title', 'woocommerce_template_loop_category_title', 10 );
		add_action( 'woocommerce_shop_loop_subcategory_title', [ $this, 'template_loop_category_title' ], 10 );

		ob_start();

		if ( $product_categories ) {
			$i = 1;
			$products_count = count( $product_categories );

			$this->total_slides = $products_count;

			if ( 'tiles' === $settings['layout'] ) {
				$this->render_tiles( $product_categories );
			} elseif ( 'carousel' === $settings['layout'] ) {
				echo '<div class="products swiper-wrapper">';

				foreach ( $product_categories as $category ) {

					include POWERPACK_ELEMENTS_PATH . 'modules/woocommerce/templates/content-product-cat-carousel.php';
					$i++;
				}

				echo '</div>';

				printf(
					'<div class="pp-screen-only elementor-screen-only" aria-live="polite" id="pp-woo-cat-carousel-status-%1$s">%2$s</div>',
					esc_attr( $this->get_id() ),
					sprintf(
						/* translators: 1: current slide number, 2: total slides */
						esc_html__( 'Showing Slide %1$s of %2$s', 'powerpack' ),
						esc_html( 1 ),
						esc_html( $this->total_slides )
					)
				);
			} else {
				echo '<ul class="elementor-grid">';

				foreach ( $product_categories as $category ) {

					include POWERPACK_ELEMENTS_PATH . 'modules/woocommerce/templates/content-product-cat.php';
					$i++;
				}

				echo '</ul>';
			}
		}

		woocommerce_reset_loop();

		$inner_content = ob_get_clean();

		if ( 'carousel' === $settings['layout'] ) {
			$this->add_render_attribute(
				'categories-inner', [
					'class' => [
						'pp-woo-categories-inner',
						'pp-swiper-slider',
						'swiper',
					],
				]
			);

			if ( is_rtl() ) {
				$this->add_render_attribute( 'categories-inner', 'dir', 'rtl' );
			}
		}

		/* Category Image */
		remove_action( 'woocommerce_before_subcategory_title', [ $this, 'woocommerce_category_thumbnail_size' ], 10 );
		add_action( 'woocommerce_before_subcategory_title', 'woocommerce_subcategory_thumbnail', 10 );

		/* Category Link */
		add_action( 'woocommerce_before_subcategory', 'woocommerce_template_loop_category_link_open', 10 );
		remove_action( 'woocommerce_before_subcategory', [ $this, 'template_loop_category_link_open' ], 10 );

		/* Category Description */
		if ( 'yes' === $settings['cat_desc'] ) {
			remove_action( 'woocommerce_after_subcategory', [ $this, 'category_description' ], 8 );
		}

		/* Category Title */
		remove_action( 'woocommerce_shop_loop_subcategory_title', [ $this, 'template_loop_category_title' ], 10 );
		add_action( 'woocommerce_shop_loop_subcategory_title', 'woocommerce_template_loop_category_title', 10 );

		/*
		 * Only the carousel needs an element of its own here, to be the swiper
		 * container that the arrows and dots sit outside of. Grid and tiles carry
		 * pp-woo-categories-inner on the widget container instead, added in
		 * render(), rather than wrapping the list in a second div that styles
		 * nothing.
		 */
		if ( 'carousel' !== $settings['layout'] ) {
			return $inner_content;
		}

		return '<div ' . $this->get_render_attribute_string( 'categories-inner' ) . '>' . $inner_content . '</div>';
	}

	/**
	 * Render the tiles layout.
	 *
	 * The tile groups are opened and closed here rather than from inside the
	 * per item template, so the markup stays balanced for any number of
	 * categories. Categories past the last group are rendered after the tiles,
	 * which is where style 2 puts its overflow grid.
	 *
	 * @since 3.0.0
	 * @access protected
	 *
	 * @param array $product_categories Category objects to render.
	 */
	protected function render_tiles( $product_categories ) {
		$settings    = $this->get_settings();
		$tiles_style = ( $settings['tiles_style'] ) ? $settings['tiles_style'] : '1';

		/*
		 * Group name => how many tiles it holds. The widths and heights behind
		 * these names live in pp-woocommerce.css, keyed on the style class.
		 */
		if ( '2' === $tiles_style ) {
			$groups = [
				'pp-woo-cat-tiles-left'  => 1,
				'pp-woo-cat-tiles-right' => 2,
			];
		} else {
			$groups = [
				'pp-woo-cat-tiles-left'   => 1,
				'pp-woo-cat-tiles-center' => 2,
				'pp-woo-cat-tiles-right'  => 1,
			];
		}

		$categories = array_values( $product_categories );
		$i          = 1;

		echo '<div class="products">';
		echo '<div class="pp-woo-cat-tiles pp-woo-cat-tiles-' . esc_attr( $tiles_style ) . '">';

		foreach ( $groups as $group_class => $size ) {
			$group = array_splice( $categories, 0, $size );

			if ( ! $group ) {
				break;
			}

			echo '<div class="' . esc_attr( $group_class ) . '">';

			foreach ( $group as $category ) {
				include POWERPACK_ELEMENTS_PATH . 'modules/woocommerce/templates/content-product-cat-tile.php';
				$i++;
			}

			echo '</div>';
		}

		echo '</div>';

		if ( $categories ) {
			// Style 2 lays its overflow out as a grid; style 1 lets the tiles run on.
			if ( '2' === $tiles_style ) {
				echo '<div class="elementor-grid">';
			}

			foreach ( $categories as $category ) {
				include POWERPACK_ELEMENTS_PATH . 'modules/woocommerce/templates/content-product-cat-tile.php';
				$i++;
			}

			if ( '2' === $tiles_style ) {
				echo '</div>';
			}
		}

		echo '</div>';
	}

	/**
	 * Render the category thumbnail at the size chosen in the panel.
	 *
	 * Replaces WooCommerce's own `woocommerce_subcategory_thumbnail()`, which
	 * is fixed to the store's category image size.
	 *
	 * @access public
	 *
	 * @param object $category Category object.
	 */
	public function woocommerce_category_thumbnail_size( $category ) {
		$settings     = $this->get_settings();
		$thumbnail_id = get_term_meta( $category->term_id, 'thumbnail_id', true );

		if ( empty( $thumbnail_id ) ) {
			woocommerce_subcategory_thumbnail( $category );
			return;
		}

		$image_alt = trim( (string) get_post_meta( $thumbnail_id, '_wp_attachment_image_alt', true ) );
		$attr      = [];

		/*
		 * The thumbnail sits inside the same link as the title, so while the
		 * title is shown the image is decorative and an empty alt stops screen
		 * readers announcing the category twice. With the title hidden the
		 * image is the only thing in the link, so it has to carry the name.
		 */
		if ( '' === $image_alt && 'yes' !== $settings['cat_title'] ) {
			$attr['alt'] = $category->name;
		}

		$size             = $settings['image_size_size'];
		$registered_sizes = get_intermediate_image_sizes();
		$registered_sizes[] = 'full';

		if ( in_array( $size, $registered_sizes, true ) ) {
			/*
			 * wp_get_attachment_image() rather than a hand built <img>: it brings
			 * the attachment's own alt text, width and height, srcset and loading
			 * attribute, none of which a bare src can provide.
			 *
			 * Note that srcset, sizes and decoding do not reach the page yet:
			 * render() still passes the whole category list through
			 * wp_kses_post(), whose allowed img attributes do not include them.
			 * They start working the moment that filter goes.
			 */
			$image = wp_get_attachment_image( $thumbnail_id, $size, false, $attr );
		} else {
			// Custom dimensions: Elementor resizes the file itself, so there is
			// no registered size for wp_get_attachment_image() to look up.
			$image_src = Group_Control_Image_Size::get_attachment_image_src( $thumbnail_id, 'image_size', $settings );

			$image = $image_src ? sprintf(
				'<img src="%1$s" alt="%2$s" loading="lazy" decoding="async">',
				esc_url( $image_src ),
				esc_attr( isset( $attr['alt'] ) ? $attr['alt'] : $image_alt )
			) : '';
		}

		if ( ! $image ) {
			// Attachment has gone away; fall back rather than print an empty src.
			woocommerce_subcategory_thumbnail( $category );
			return;
		}

		echo wp_kses_post( $image );
	}

	/**
	 * Category Link Open.
	 *
	 * @access public
	 *
	 * @param object $category Category object.
	 */
	public function template_loop_category_link_open( $category ) {
		/**
		 * Filters the category link used by the Woo - Categories widget.
		 *
		 * @since 1.4.2
		 *
		 * @param string $link     Escaped category archive URL.
		 * @param object $category Category object.
		 */
		$link = apply_filters( 'pp_woo_category_link', esc_url( get_term_link( $category, 'product_cat' ) ), $category );

		/*
		 * pp-product-cat-inner used to be a div wrapped around everything inside
		 * this link. The link is already display:block and position:relative, so
		 * the div only repeated it; the class stays here so existing custom CSS
		 * written against it keeps matching.
		 */
		echo '<a class="pp-product-cat-inner" href="' . esc_url( $link ) . '">';
	}

	/**
	 * Content Start.
	 *
	 * @access public
	 *
	 * @param object $category Category object.
	 */
	public function category_content_start( $category ) {
		echo '<div class="pp-product-cat-content-wrap">';
		echo '<div class="pp-product-cat-content">';
	}

	/**
	 * Content End.
	 *
	 * @access public
	 *
	 * @param object $category Category object.
	 */
	public function category_content_end( $category ) {
		echo '</div>';
		echo '</div>';
	}

	/**
	 * Category Description.
	 *
	 * @access public
	 *
	 * @param object $category Category object.
	 */
	public function category_description( $category ) {

		$settings = $this->get_settings();

		if ( ! $category || empty( $category->description ) ) {
			return;
		}

		$description = wc_format_content( $category->description );

		if ( $settings['category_desc_limit'] ) {
			$description = wp_trim_words( $description, $settings['category_desc_limit'], '' );
		}

		// The inner pp-term-description wrapper is gone: it carried no styling of
		// its own and every description control targets pp-product-cat-desc.
		echo '<div class="pp-product-cat-desc">' . $description . '</div>';//phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- WooCommerce term description, filtered by wp_kses_post() in render().
	}

	/**
	 * Show the subcategory title in the product loop.
	 *
	 * @access public
	 *
	 * @param object $category Category object.
	 */
	public function template_loop_category_title( $category ) {

		$settings = $this->get_settings();

		$output = '<div class="pp-category__title-wrap">';

		if ( 'yes' === $settings['cat_title'] ) {
			$title_tag = PP_Helper::validate_html_tag( $settings['cat_title_html_tag'] );

			$output .= sprintf(
				'<%1$s class="woocommerce-loop-category__title">%2$s</%1$s>',
				$title_tag,
				esc_html( $category->name )
			);
		}

		if ( 'yes' === $settings['product_count'] && $category->count > 0 ) {
			$output .= sprintf(
				'<span class="pp-count">%s</span>',
				sprintf(
					/* translators: %s: number of products in the category. */
					_nx( '%s Product', '%s Products', $category->count, 'product categories', 'powerpack' ),
					number_format_i18n( $category->count )
				)
			);
		}

		$output .= '</div>';

		echo wp_kses_post( $output );
	}

	/**
	 * Set slider attributes.
	 *
	 * @access public
	 */
	public function set_slider_attr() {

		$settings = $this->get_settings();

		if ( 'carousel' !== $settings['layout'] ) {
			return;
		}

		$slides_to_show = ( isset( $settings['slides_to_show'] ) && '' !== $settings['slides_to_show'] ) ? absint( $settings['slides_to_show'] ) : 4;
		$slides_to_show_tablet  = ( isset( $settings['slides_to_show_tablet'] ) && '' !== $settings['slides_to_show_tablet'] ) ? absint( $settings['slides_to_show_tablet'] ) : 3;
		$slides_to_show_mobile  = ( isset( $settings['slides_to_show_mobile'] ) && '' !== $settings['slides_to_show_mobile'] ) ? absint( $settings['slides_to_show_mobile'] ) : 1;

		$slides_to_scroll = ( isset( $settings['slides_to_scroll'] ) && $settings['slides_to_scroll'] ) ? absint( $settings['slides_to_scroll'] ) : 1;
		$slides_to_scroll_tablet  = ( isset( $settings['slides_to_scroll_tablet'] ) && $settings['slides_to_scroll_tablet'] ) ? absint( $settings['slides_to_scroll_tablet'] ) : 1;
		$slides_to_scroll_mobile  = ( isset( $settings['slides_to_scroll_mobile'] ) && $settings['slides_to_scroll_mobile'] ) ? absint( $settings['slides_to_scroll_mobile'] ) : 1;

		$slider_options = [
			'direction'        => 'horizontal',
			'slides_per_view'  => $slides_to_show,
			'slides_to_scroll' => $slides_to_scroll,
			'speed'            => ( $settings['transition_speed'] ) ? absint( $settings['transition_speed'] ) : 600,
			'space_between'    => ( $settings['column_gap']['size'] ) ? $settings['column_gap']['size'] : 10,
			'loop'             => ( 'yes' === $settings['infinite'] ),
			'auto_height'      => true,
		];

		if ( 'yes' === $settings['autoplay'] ) {
			$autoplay_speed = 999999;
			$slider_options['autoplay'] = 'yes';

			if ( ! empty( $settings['autoplay_speed'] ) ) {
				$autoplay_speed = absint( $settings['autoplay_speed'] );
			}

			$slider_options['autoplay_speed'] = $autoplay_speed;
		}

		if ( 'yes' === $settings['dots'] ) {
			$slider_options['pagination'] = 'bullets';
		}

		if ( 'yes' === $settings['arrows'] ) {
			$slider_options['show_arrows'] = true;
		}

		$breakpoints = PP_Helper::elementor()->breakpoints->get_active_breakpoints();

		foreach ( $breakpoints as $device => $breakpoint ) {
			if ( in_array( $device, [ 'mobile', 'tablet', 'desktop' ], true ) ) {
				switch ( $device ) {
					case 'desktop':
						$slider_options['slides_per_view'] = absint( $slides_to_show );
						$slider_options['slides_to_scroll'] = absint( $slides_to_scroll );
						$slider_options['space_between'] = ( isset( $settings['column_gap']['size'] ) && $settings['column_gap']['size'] ) ? absint( $settings['column_gap']['size'] ) : 10;
						break;
					case 'tablet':
						$slider_options['slides_per_view_tablet'] = absint( $slides_to_show_tablet );
						$slider_options['slides_to_scroll_tablet'] = absint( $slides_to_scroll_tablet );
						$slider_options['space_between_tablet'] = ( isset( $settings['column_gap_tablet']['size'] ) && $settings['column_gap_tablet']['size'] ) ? absint( $settings['column_gap_tablet']['size'] ) : 10;
						break;
					case 'mobile':
						$slider_options['slides_per_view_mobile'] = absint( $slides_to_show_mobile );
						$slider_options['slides_to_scroll_mobile'] = absint( $slides_to_scroll_mobile );
						$slider_options['space_between_mobile'] = ( isset( $settings['column_gap_mobile']['size'] ) && $settings['column_gap_mobile']['size'] ) ? absint( $settings['column_gap_mobile']['size'] ) : 10;
						break;
				}
			} else {
				if ( isset( $settings['slides_to_show_' . $device]['size'] ) && $settings['slides_to_show_' . $device]['size'] ) {
					$slider_options['slides_to_show_' . $device] = absint( $settings['slides_to_show_' . $device]['size'] );
				}

				if ( isset( $settings['slides_to_scroll_' . $device]['size'] ) && $settings['slides_to_scroll_' . $device]['size'] ) {
					$slider_options['slides_to_scroll_' . $device] = absint( $settings['slides_to_scroll_' . $device]['size'] );
				}

				if ( isset( $settings['column_gap_' . $device]['size'] ) && $settings['column_gap_' . $device]['size'] ) {
					$slider_options['space_between_' . $device] = absint( $settings['column_gap_' . $device]['size'] );
				}
			}
		}

		$this->add_render_attribute(
			'categories-inner', [
				'data-slider-settings' => wp_json_encode( $slider_options ),
			]
		);
	}

	/**
	 * Render carousel dots output on the frontend.
	 *
	 * Written in PHP and used to generate the final HTML.
	 *
	 * @access protected
	 */
	protected function render_dots() {
		$settings = $this->get_settings();

		if ( 'carousel' !== $settings['layout'] ) {
			return;
		}

		if ( 'yes' === $settings['dots'] ) {
			?>
			<!-- Add Pagination -->
			<div class="swiper-pagination swiper-pagination-<?php echo esc_attr( $this->get_id() ); ?>"></div>
			<?php
		}
	}

	/**
	 * Render carousel arrows output on the frontend.
	 *
	 * Written in PHP and used to generate the final HTML.
	 *
	 * @access protected
	 */
	protected function render_arrows() {
		$settings = $this->get_settings();

		if ( 'carousel' !== $settings['layout'] ) {
			return;
		}

		$migration_allowed = Icons_Manager::is_migration_allowed();

		if ( ! isset( $settings['arrow'] ) && ! $migration_allowed ) {
			// add old default.
			$settings['arrow'] = 'fa fa-angle-right';
		}

		$has_icon = ! empty( $settings['arrow'] );

		if ( ! $has_icon && ! empty( $settings['select_arrow']['value'] ) ) {
			$has_icon = true;
		}

		if ( ! empty( $settings['arrow'] ) ) {
			$this->add_render_attribute( 'arrow-icon', 'class', $settings['arrow'] );
			$this->add_render_attribute( 'arrow-icon', 'aria-hidden', 'true' );
		}

		$migrated = isset( $settings['__fa4_migrated']['select_arrow'] );
		$is_new = ! isset( $settings['arrow'] ) && $migration_allowed;

		if ( 'yes' === $settings['arrows'] ) {
			if ( $has_icon ) {
				if ( $is_new || $migrated ) {
					$next_arrow = $settings['select_arrow'];
					$prev_arrow = str_replace( 'right', 'left', $settings['select_arrow'] );
				} else {
					$next_arrow = $settings['arrow'];
					$prev_arrow = str_replace( 'right', 'left', $settings['arrow'] );
				}
			} else {
				$next_arrow = 'fa fa-angle-right';
				$prev_arrow = 'fa fa-angle-left';
			}

			if ( ! empty( $settings['arrow'] ) || ( ! empty( $settings['select_arrow']['value'] ) && $is_new ) ) { ?>
				<div class="pp-slider-arrow pp-arrow-prev elementor-swiper-button-prev swiper-button-prev-<?php echo esc_attr( $this->get_id() ); ?>" role="button" tabindex="0" aria-label="<?php echo esc_attr__( 'Previous slide', 'powerpack' ); ?>">
					<?php if ( $is_new || $migrated ) :
						Icons_Manager::render_icon( $prev_arrow, [ 'aria-hidden' => 'true' ] );
					else : ?>
						<i <?php $this->print_render_attribute_string( 'arrow-icon' ); ?>></i>
					<?php endif; ?>
				</div>
				<div class="pp-slider-arrow pp-arrow-next elementor-swiper-button-next swiper-button-next-<?php echo esc_attr( $this->get_id() ); ?>" role="button" tabindex="0" aria-label="<?php echo esc_attr__( 'Next slide', 'powerpack' ); ?>">
					<?php if ( $is_new || $migrated ) :
						Icons_Manager::render_icon( $next_arrow, [ 'aria-hidden' => 'true' ] );
					else : ?>
						<i <?php $this->print_render_attribute_string( 'arrow-icon' ); ?>></i>
					<?php endif; ?>
				</div>
			<?php }
		}
	}

	/**
	 * Render output on the frontend.
	 *
	 * Written in PHP and used to generate the final HTML.
	 *
	 * @access protected
	 */
	protected function render() {
		$settings = $this->get_settings();

		$this->add_render_attribute( 'container', 'class', [
			'pp-woocommerce',
			'pp-woo-categories',
			'pp-woo-categories-' . $settings['layout'],
		] );

		if ( 'tiles' === $settings['layout'] ) {
			$this->add_render_attribute( 'container', 'class', [
				'pp-woo-categories-overlay',
			] );
		} else {
			$this->add_render_attribute( 'container', 'class', [
				'pp-woo-categories-' . $settings['content_position'],
			] );
		}

		if ( 'carousel' === $settings['layout'] ) {
			$this->add_render_attribute( 'container', 'class', [
				'swiper-container-wrap',
			] );

			if ( $settings['dots_position'] ) {
				$this->add_render_attribute( 'container', 'class', 'swiper-container-wrap-dots-' . $settings['dots_position'] );
			}

			/*
			 * Names the carousel for screen readers and tells them it is one, so
			 * the slide status message announced from the live region inside has
			 * something to belong to.
			 */
			$this->add_render_attribute( 'container', [
				'role'                 => 'region',
				'aria-roledescription' => 'carousel',
				'aria-label'           => esc_attr__( 'Product categories', 'powerpack' ),
			] );
		} else {
			// The carousel gets this class on its own swiper element instead.
			$this->add_render_attribute( 'container', 'class', 'pp-woo-categories-inner' );
		}

		$this->set_slider_attr();
		?>
		<div <?php $this->print_render_attribute_string( 'container' ); ?>>
			<?php echo wp_kses_post( $this->query_product_categories() ); ?>
			<?php
			if ( 'carousel' === $settings['layout'] ) {
				$this->render_dots();
				$this->render_arrows();
			}
			?>
		</div>
		<?php
	}
}
