<?php
/**
 * Preview script helper class for handle exceptional element
 *
 * @package kirki
 */

namespace Kirki\Frontend\Preview;

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

use Kirki\Ajax\Symbol;
use Kirki\HelperFunctions;

/**
 * ExceptionalElements Class
 */
class ExceptionalElements {
	/**
	 * Get this exceptional element
	 *
	 * @param array $this_data single element block.
	 * @param array $attributes single element all attributes.
	 * @param array $options single element all options.
	 * @return string HTML markup.
	 */
	public function get_this_exceptional_element( $this_data, $attributes, $options ) {
		switch ( $this_data['name'] ) {
			case 'custom-code': {
				return $this->custom_code( $this_data, $attributes );
			}
			case 'form': {
				return $this->form_element( $this_data, $attributes, $options );
			}
			case 'map':
			case 'google-map': {
				return $this->map_element( $this_data, $attributes );
			}
			case 'svg':
			case 'svg-icon':
			{
				return $this->svg_and_icon_element( $this_data, $attributes, $options );
			}
			case 'textarea': {
				return '<textarea ' . $attributes . '></textarea>';
			}
			case 'select': {
				return $this->select_element( $this_data, $attributes, $options );
			}
			case 'section': {
					return $this->section_element( $this_data, $attributes, $options );
			}
			case 'video': {
				return $this->video_element( $this_data, $attributes, $options );
			}
			case 'radio-group': {
				return $this->radio_group( $this_data, $attributes );
			}
			case 'checkbox-element': {
				return $this->checkbox_element( $this_data, $attributes, $options );
			}
			case 'radio-button': {
				return '<input type="radio" ' . $attributes . ' />';
			}
			case 'image': {
				return $this->image_element( $this_data, $attributes, $options );
			}
			case 'link-block': {
					return $this->link_block_element( $this_data, $attributes, $options );
			}

			case 'file-upload-inner': {
					return $this->file_input_element( $this_data, $attributes, $options );
			}

			case 'file-upload-threshold-text': {
					return $this->file_upload_threshold_text( $this_data, $attributes, $options );
			}

			case 'file-upload': {
					return $this->file_upload_element( $this_data, $attributes, $options );
			}
			case 'slider':
			case 'collection': {
				$element_name = $this_data['name'];
				$properties   = $this_data['properties'];

				$dynamic_content = $element_name === 'slider'
					? ( $properties['dynamicSliderContent'] ?? array() )
					: ( $properties['dynamicContent'] ?? array() );

				if ( ! empty( $dynamic_content['offset'] ) ) {
					$options['offset'] = (int) $dynamic_content['offset'];
				}

				if ( $element_name === 'slider' ) {
					$options['slider_mode']  = $properties['slider']['mode'] ?? 'manual'; // default manual
					$options['element_name'] = $element_name;
					$slider_mask_id          = $this_data['children'][0];

					if ( $slider_mask_id && isset( $this->data[ $slider_mask_id ] ) ) {
						$slider_mask_data                = $this->data[ $slider_mask_id ];
						$options['slider_mask_children'] = $slider_mask_data['children'] ?? array();
					}
				}

				$children = array();

				if ( empty( $dynamic_content['collectionType'] ) ) {
					$dynamic_content['collectionType'] = 'posts'; // default value
				}

				$children = $this->construct_items_collection_markup( $dynamic_content, $this_data, $options );

				return $this->construct_collection_markup( $children, $this_data, $attributes, $element_name, $options );
			}
			case 'loading': {
				return $this->collection_loading_element( $this_data, $attributes, $options );
			}
			case 'terms': // TODO: migrate and remove
			case 'users': // TODO: migrate and remove
			case 'collection-wrapper': // TODO: migrate and remove
			case 'slider_mask':
			case 'items': {
					$tag                  = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
					$collection           = isset( $options['collection'] ) ? $options['collection'] : array();
					$itemType             = isset( $options['itemType'] ) ? $options['itemType'] : 'post';
					$collection_item_id   = $this_data['children'][0];
					$slider_mask_children = $this_data['children'];
					$slider_mode          = $options['slider_mode'] ?? 'manual';
					$is_slider            = isset( $options['element_name'] ) && $options['element_name'] === 'slider';

					$children = array();

				if ( ! $options ) {
					$options = array();
				}

				if ( $is_slider && $slider_mode === 'manual' ) {
					foreach ( $slider_mask_children as $key => $child_id ) {
						$children[] = $this->recGenHTML( $child_id, $options );
					}
				} else { // for collection and slider (dynamic)
					foreach ( $collection as $key => $collection_item ) {
						$item_index = HelperFunctions::get_current_item_index( $key + 1, $options );
						$options    = array_merge(
							$options,
							array(
								'itemType'   => $itemType,
								$itemType    => $collection_item,
								'item_index' => $item_index,
							)
						);

						$children[] = HelperFunctions::rec_update_data_id_then_return_new_html( $this->data, $this->style_blocks, $collection_item_id, $options, ( $key === 0 ) );
					};
				}

				return $this->get_template(
					'items',
					array(
						'attributes' => $attributes,
						'children'   => $children,
						'tag'        => $tag,
					)
				);
			}

			case 'pagination': {
				$tag             = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
				$markup          = '';
				$show_pagination = isset( $options['pagination'] ) ? $options['pagination'] : true;
				$pagination_type = isset( $options['pagination_type'] ) ? $options['pagination_type'] : 'numeric';
				$offset          = isset( $options['offset'] ) ? (int) $options['offset'] : 0;

				if ( $show_pagination ) {
					$collection_count = 0;

					if ( isset( $options['itemType'], $options['collection_count'] ) ) {
						$collection_count = $options['collection_count'];
					}

					$current_page   = isset( $options['page_no'] ) ? $options['page_no'] : 1;
					$items_per_page = isset( $options['items_per_page'] ) ? $options['items_per_page'] : 3;
					$total_pages    = $collection_count ? (int) ceil( ( $collection_count - $offset ) / $items_per_page ) : 0;
						// $pagination_item_id = $this_data['children'][0];
						$pagination_item_id = isset( $this_data['children'][0] ) ? $this_data['children'][0] : '';

					$children = array();

					// pagination type: numeric or infinite_scroll
					if ( $pagination_type === 'numeric' ) {
						$start = 1;
						$end   = $total_pages;

						/**
						 * custom for large pagination start
						 */
						// Determine the range to display
						$range      = 10;
						$half_range = floor( $range / 2 );

						// Calculate new $start and $end
						$start = max( 1, $current_page - $half_range );
						$end   = min( $total_pages, $current_page + $half_range );

						// Adjust $start and $end if at the boundaries
						if ( $end - $start < $range - 1 ) {
							if ( $start == 1 ) {
									$end = min( $start + $range - 1, $total_pages );
							} else {
									$start = max( $end - $range + 1, 1 );
							}
						}
						/**
						 * custom for large pagination end
						 */

						if ( $end > 1 ) {
							for ( $i = $start; $i <= $end; $i++ ) {
								$options    = array(
									'page_number'  => $i,
									'current_page' => $current_page === $i,
								);
								$children[] = HelperFunctions::rec_update_data_id_then_return_new_html( $this->data, $this->style_blocks, $pagination_item_id, $options, ( $i === $start ) );
							}
						}

						$markup = $this->get_template(
							'pagination',
							array(
								'attributes' => $attributes,
								'children'   => $children,
								'tag'        => $tag,
							)
						);
					} elseif ( $pagination_type === 'infinite_scroll' ) {
						$markup = $this->get_template(
							'pagination',
							array(
								'attributes' => $attributes . ' data-total-pages="' . $total_pages . '" data-current-page="' . $current_page . '"' . ' data-pagination-type="' . $pagination_type . '"' . 'style="height:1px "',
								'children'   => $children,
								'tag'        => $tag,
							)
						);
					} elseif ( $pagination_type === 'load_more' && $current_page !== $total_pages ) {
						$children = isset( $this_data['children'] ) ? $this_data['children'] : array();

						$child_markup = $this->construct_children_markup( $children, $options );

						$attr = $attributes . ' data-total-pages="' . $total_pages . '" data-current-page="' . $current_page . '"' . ' data-pagination-type="' . $pagination_type . '"';
						return "<$tag $attr>
										$child_markup
									</$tag>";
					}
				}

				return $markup;
			}

			case 'pagination-item': {
				$tag          = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
				$current_page = isset( $options['current_page'] ) ? $options['current_page'] : false;
				$page_number  = isset( $options['page_number'] ) ? $options['page_number'] : false;

				$children = array();

				foreach ( $this_data['children'] as $child ) {
						$children[] = $this->recGenHTML(
							$child,
							array(
								'page_number' => $page_number,
							)
						);
				}

				return $this->get_template(
					'pagination-item',
					array(
						'attributes'   => $attributes,
						'children'     => $children,
						'current_page' => $current_page,
						'page_number'  => $page_number,
						'tag'          => $tag,
					)
				);
			}

			case 'pagination-number': {
				$tag         = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'span';
				$page_number = isset( $options['page_number'] ) ? $options['page_number'] : 1;

				return $this->get_template(
					'pagination-number',
					array(
						'attributes'  => $attributes,
						'page_number' => $page_number,
						'tag'         => $tag,
					)
				);
			}

			case 'common': {
					$tag  = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
					$type = isset( $this_data['properties']['type'] ) ? $this_data['properties']['type'] : false;

				if ( $type ) {
					$attributes .= ' data-kirki-type="' . $type . '"';
				}

					$children = isset( $this_data['children'] ) ? $this_data['children'] : array();

					$child_markup = $this->construct_children_markup( $children, $options );

				return "<$tag $attributes>
										$child_markup
									</$tag>";
			}

			case 'symbol': {
				return $this->generate_symbol_html( $this_data, $attributes, $options );
			}
			case 'popup-body': {
				return $this->popup_element( $this_data, $attributes, $options );
			}

			case 'button': {
				return $this->button_element( $this_data, $attributes, $options );
			}

			case 'navigation': {
					return $this->navigation_element( $this_data, $attributes, $options );
			}

			case 'navigation-item': {
				return $this->navigation_item_element($this_data, $attributes, $options);
			}

			case 'navigation-items': {
					return $this->navigation_items_element( $this_data, $attributes, $options );
			}

			case 'slider_nav':{
				return $this->slider_nav_element( $this_data, $attributes, $options );
			}
			case 'tabs':{
				return $this->tabs_element( $this_data, $attributes, $options );
			}
			case 'tab':{
				return $this->tab_element( $this_data, $attributes, $options );
			}
			case 'tab_pane':{
				return $this->tab_pane_element( $this_data, $attributes, $options );
			}
			case 'tab_content':
			case 'tab_menu':{
				return $this->tab_menu_and_content_element( $this_data, $attributes, $options );
			}
		}
	}

	/**
	 * Generate collection loading element markup
	 *
	 * @param array $this_data single element block.
	 * @param array $attributes single element all attributes.
	 * @param array $options single element all options.
	 * @return string HTML markup.
	 */
	private function collection_loading_element( $this_data, $attributes, $options ) {
		$tag = isset( $this_data['properties'], $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';

		$children_markup = $this->construct_children_markup( isset( $this_data['children'] ) ? $this_data['children'] : array(), $options );

		return "<$tag $attributes kirki-collection=\"loading\" data-element_hide=\"true\">
				$children_markup
			</$tag>";
	}

	/**
	 * Generate section element markup
	 *
	 * @param array $this_data single element block.
	 * @param array $attributes single element all attributes.
	 * @param array $options single element all options.
	 * @return string HTML markup.
	 */
	private function section_element( $this_data, $attributes, $options ) {
		$id = isset( $this_data['id'] ) ? $this_data['id'] : '';
		if ( $id ) {
			$id = $this->get_unique_section_id_from_title( $id );
		}

		$tag = isset( $this_data['properties'], $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'a';

		$children_markup = $this->construct_children_markup( isset( $this_data['children'] ) ? $this_data['children'] : array(), $options );

		return "<$tag $attributes id=\"$id\">
				$children_markup
			</$tag>";
	}

	private function navigation_element( $this_data, $attributes, $options ) {
		$tag       = isset( $this_data['properties'], $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'a';

		$hamburger = isset($this_data['properties']['navigation']['hamburger']) ? $this_data['properties']['navigation']['hamburger'] : false;

		if ( ! is_array( $options ) ) {
			$options = array();
		}

		if ( ! $options ) {
			$options = array();
		}
		$options = array_merge(
			$options,
			array(
				'navigation' => array(
					'id'        => $this_data['id'],
					'hamburger' => $hamburger,
					'showNavigationChildrenOn' => isset($this_data['properties']['navigation']['showNavigationChildrenOn']) ? $this_data['properties']['navigation']['showNavigationChildrenOn'] : 'hover',
				),
			)
		);

		$children_markup = $this->construct_children_markup( isset( $this_data['children'] ) ? $this_data['children'] : array(), $options );

		return "<$tag $attributes>
				$children_markup
			</$tag>";
	}

	private function navigation_item_element($this_data, $attributes, $options)
	{
		$tag = isset($this_data['properties'], $this_data['properties']['tag']) ? $this_data['properties']['tag'] : 'a';

		$children_markup = $this->construct_children_markup(isset($this_data['children']) ? $this_data['children'] : array(), $options);

		$extra_attributes = '';

		$show_on = 'hover';

		// check showNavigationChildrenOn is hover or click or always then add kirki-navigation-item-trigger-on='hover'/'click'/'always'
		if (isset($this_data['properties']['navigationItem']['showNavigationChildrenOn'])) {
			$show_on = $this_data['properties']['navigationItem']['showNavigationChildrenOn'];
			$extra_attributes .= ' kirki-navigation-item-trigger-on="' . $show_on . '"';
		} else if (isset($options['navigation']['showNavigationChildrenOn'], $options['navigation']['hamburger']) && $options['navigation']['hamburger']) {
			$show_on = $options['navigation']['showNavigationChildrenOn'];
			$extra_attributes .= ' kirki-navigation-item-trigger-on="' . $show_on . '"';
		} else {
			$extra_attributes .= ' kirki-navigation-item-trigger-on="hover"';
		}

		if ('always' !== $show_on) {
			$extra_attributes .= ' kirki-navigation-item-dismiss-on="' . ($this_data['properties']['navigationItem']['hideNavigationChildrenOn'] ?? 'mouseleave') . '"';
		}

		if (!$options) {
			$options = array();
		}

		// add if kirki-navigation="nav-item" has in $this_data['properties']['attributes'] then set inside_nav_item = true
		$options = array_merge(
			$options,
			array(
				'inside_nav_item' => isset($this_data['properties']['attributes']['kirki-navigation']) && $this_data['properties']['attributes']['kirki-navigation'] === 'nav-item',
			)
		);

		$children_markup = $this->construct_children_markup(isset($this_data['children']) ? $this_data['children'] : array(), $options);

		return "<$tag $attributes $extra_attributes>
				$children_markup
			</$tag>";
	}

	private function navigation_items_element($this_data, $attributes, $options)
	{

		$tag = isset($this_data['properties'], $this_data['properties']['tag']) ? $this_data['properties']['tag'] : 'a';

		$extra_attr = isset($options['inside_navigation']) && $options['inside_navigation'] ? 'kirki-navigation-hide="true"' : '';

		if (isset($options['navigation']['hamburger']) && $options['navigation']['hamburger']) {
			$extra_attr .= ' kirki-navigation-type="close"';
		}

		if (!$options) {
			$options = array();
		}
		$options = array_merge(
			$options,
			array(
				'inside_navigation' => true,
			)
		);

		$children_markup = $this->construct_children_markup(isset($this_data['children']) ? $this_data['children'] : array(), $options);
		// check it has kirki-menu-wrapper: true as attribute
		// if (isset($this_data['properties']['attributes']['kirki-menu-wrapper']) && $this_data['properties']['attributes']['kirki-menu-wrapper'] === 'true') {
		if (isset($options['inside_nav_item']) && $options['inside_nav_item'] === true) {
			// Match the content inside class="..." and data-kirki="..."
			preg_match('/class="([^"]+)"/', $attributes, $classMatch);
			preg_match('/data-kirki="([^"]+)"/', $attributes, $dataMatch);

			$class = $classMatch[1] ?? null;
			$data_kirki = $dataMatch[1] ?? null;

			return "
							<div kirki-menu-wrapper-div='true'>
							<$tag class='$class' data-kirki='$data_kirki'>
							$children_markup
							</$tag>
							</div>
					 ";
		} else {
			return "<$tag $attributes $extra_attr>
			$children_markup
		</$tag>";
		}

	}

	private function form_element( $this_data, $attributes, $options ) {
		$properties = $this_data['properties'];
		$post_id    = HelperFunctions::get_post_id_if_possible_from_url();
		$form_id    = $this_data['id'];
		$post_data  = $form_id . '|' . $post_id;
		$form_data  = $post_data . '|' . wp_hash( $post_data );
		// phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
		$form_id_base64 = base64_encode( base64_encode( $form_data ) );

		$form_nonce_field = wp_nonce_field( 'wp_rest', '_wpnonce', true, false );

		if ( ! $options ) {
			$options = array();
		}

		$options = array_merge(
			$options,
			array(
				'form' => array(
					'id' => $form_id,
				),
			)
		);

		$form_children_markup = $this->construct_children_markup( isset( $this_data['children'] ) ? $this_data['children'] : array(), $options );

		if ( isset( $properties['form']['type'] ) && $properties['form']['type'] !== 'external' ) {
			$attributes = $this->getAllAttributes(
				$this_data,
				array(
					'action' => false,
					'method' => false,
					'rest'   => true,
				),
			);
		}

		return "<form $attributes>
				<input type=\"hidden\" name=\"_kirki_form\" value=\"$form_id_base64\" />
				$form_nonce_field
				$form_children_markup
			</form>";
	}

	private function select_element( $this_data, $attributes, $options ) {
		$properties       = $this_data['properties'];
		$select_options   = isset( $properties['options']['list'] ) ? $properties['options']['list'] : array();
				$selected = isset( $properties['options']['selectedOption'] ) ? $properties['options']['selectedOption'] : '';
				$html     = '<select ' . $attributes . '>';
		foreach ( $select_options as $option ) {
			$html .= "<option value='";
			$html .= $option['value'] . "'";
			$html .= $selected === $option['value'] ? ' selected' : '';
			$html .= '>';
			$html .= $option['contents'];
			$html .= '</option>';
		}
				$html .= '</select>';

				return $html;
	}

	/**
	 * Generate checkbox element markup
	 *
	 * @param array $this_data single element block.
	 * @param array $attributes single element all attributes.
	 * @param array $options single element all options.
	 * @return string HTML markup.
	 */
	private function checkbox_element( $this_data, $attributes, $options ) {
		$relation_type = isset( $options['relation_type'] ) ? $options['relation_type'] : 'posts';
		if ( ! isset( $options['form'] ) ) {
			// Start: Filter functionality
			if ( $relation_type === 'posts' ) {
				$checked_ids = isset( $options['selected_post_ids'] ) ? $options['selected_post_ids'] : array();
				$checked     = in_array( (string) $options['post']->ID, $checked_ids, true );

				if ( $checked ) {
					$attributes = 'checked ' . $attributes;
				}

				$attributes = "name='cm_post' value='" . $options['post']->ID . "' " . $attributes;
			} elseif ( $relation_type === 'terms' ) {
				$taxonomy = $options['term']['taxonomy'];
				$term_id  = $options['term']['term_id'];

				$checked_ids = isset( $options['selected_taxonomies'] ) ? $options['selected_taxonomies'] : array();
				$checked     = in_array( (string) $term_id, $checked_ids, true );

				if ( $checked ) {
					$attributes = 'checked ' . $attributes;
				}

				$attributes = "name='$taxonomy' value='$term_id' " . $attributes;
			}
		}
		// End: Filter functionality

		return '<input type="checkbox" ' . $attributes . ' />';
	}

	private function link_block_element( $this_data, $attributes, $options ) {
		$href = $this->get_href_value( $this_data, $options );

		$preload_link = '';

		if ( $href ) {
			$attributes = preg_replace( '/href="([^"]+")/i', '', $attributes );

			// check if this link is active
			$attributes = $this->add_link_active_class( $href, $attributes, $this_data, $options );

			$preload_link = $this->get_preload_link( $href, $this_data );
		}

		return '<a ' . $attributes . ' ' . ' href="' . $href . '" >' . $this->construct_children_markup( isset( $this_data['children'] ) ? $this_data['children'] : array(), $options ) . '</a>' . $preload_link;
	}

	private function button_element( $this_data, $attributes, $options ) {
		$href         = $this->get_href_value( $this_data, $options );
		$preload_link = '';

		if ( $href ) {
			$attributes = preg_replace( '/href="([^"]+")/i', '', $attributes );

			// check if this link is active
			$attributes = $this->add_link_active_class( $href, $attributes, $this_data, $options );

			$preload_link = $this->get_preload_link( $href, $this_data );
		}

		$children_markup = $this->construct_children_markup( isset( $this_data['children'] ) ? $this_data['children'] : array(), $options );
		$tag             = isset( $this_data['properties'], $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'button';
		if ( $href ) {
			$tag = 'a';
		}

		return "<$tag $attributes href=\"$href\">
			$children_markup
		</$tag>
		$preload_link";
	}

	private function svg_and_icon_element( $this_data, $attributes, $options ) {
		$properties = $this_data['properties'];
		$svg        = isset( $properties['svgOuterHtml'] ) ? $properties['svgOuterHtml'] : '';
		return str_replace( '<svg', "<svg $attributes", $svg );
	}

	/**
	 * Construct children markup
	 *
	 * @param array $children single element all childrens.
	 * @param array $options single element all options.
	 * @return string HTML markup.
	 */
	private function construct_children_markup( $children, $options ) {
		$markup = '';
		if ( isset( $children ) && is_array( $children ) ) {
			foreach ( $children as $child ) {
				$markup .= $this->recGenHTML( $child, $options );
			}
		}
		return $markup;
	}
	private function construct_items_collection_markup( $dynamic_content, $this_data, $options ) {
		$collection_type = isset( $dynamic_content['collectionType'] ) ? $dynamic_content['collectionType'] : 'posts';
		$show_pagination = isset( $dynamic_content['pagination'] ) ? $dynamic_content['pagination'] : true;
		$pagination_type = isset( $dynamic_content['pagination_type'] ) ? $dynamic_content['pagination_type'] : 'numeric';

		if ( ! $options ) {
			$options = array();
		}

		$items_data = Utils::get_items_data_from_dynamic_contents( $dynamic_content, $options );

		$data       = $items_data['data'];
		$pagination = $items_data['pagination'];
		$itemType   = $items_data['itemType'];

		$additional_options = array();

		// START: Filter functionality
		if ( $collection_type === 'posts' && isset( $dynamic_content['post_type'] ) && $dynamic_content['post_type'] ) {
			if ( isset( $_GET['post'][ $dynamic_content['post_type'] ] ) && is_array( $_GET['post'][ $dynamic_content['post_type'] ] ) ) {
				$additional_options['selected_post_ids'] = $_GET['post'][ $dynamic_content['post_type'] ];
			}
		} elseif ( $collection_type === 'terms' ) {
			if ( isset( $_GET['taxonomy'][ $dynamic_content['taxonomy'] ] ) && is_array( $_GET['taxonomy'][ $dynamic_content['taxonomy'] ] ) ) {
				$additional_options['selected_taxonomies'] = $_GET['taxonomy'][ $dynamic_content['taxonomy'] ];
			}
		}

		$additional_options['relation_type'] = $collection_type;
		// END: Filter functionality

		$options = array_merge(
			$options,
			$additional_options
		);

		$children = array();

		foreach ( $this_data['children'] as $child ) {

			if ( count( $data ) > 0 ) {
				if ( isset( $this->data[ $child ] ) && $this->data[ $child ]['name'] === 'empty' ) {
					continue;
				}
			} elseif ( count( $data ) === 0 ) {
				if ( isset( $this->data[ $child ] ) && ( $this->data[ $child ]['name'] === 'pagination' || $this->data[ $child ]['name'] === 'items' ) ) {
					continue;
				}
			}

			$children[] = $this->recGenHTML(
				$child,
				array_merge(
					$options,
					array(
						'collection'       => $data,
						'collection_count' => $pagination['total_count'] ?? 0,
						'items_per_page'   => $pagination['per_page'] ?? 0,
						'page_no'          => $pagination['current_page'] ?? 1,
						'pagination'       => $show_pagination,
						'itemType'	=>  $itemType,
						'pagination_type'	=> $pagination_type,
						'inside_collection' => true
					)
				)
			);
		}

		return $children;
	}


	/**
	 * Construct collection markup
	 *
	 * @param array $collection single element collection data.
	 * @param array $this_data single element.
	 * @param array $attributes single element all attributes.
	 * @return string HTML markup.
	 */
	private function construct_collection_markup( $children, $this_data, $attributes, $element_name = 'collection', $options=[] ) {
		$tag = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';

		$collection_info = $this->get_collection_info($options, $this_data);

		if ( is_array( $children ) ) {
			return $this->get_template(
				'collection',
				array(
					'data'       => $collection_info,
					'attributes' => $attributes,
					'children'   => $children,
					'tag'        => $tag,
				)
			);
		} else {
			return '';
		}
	}

	public function get_collection_info($options, $this_data) {
		$collection_info = array(
			'post_id' => isset($options['post']) ? $options['post']->ID : false,
			'collection_data_id' => isset($this_data['original_id']) ? $this_data['original_id'] :$this_data['id']
		);
		if(isset($options['kirki_template_id']) && $options['kirki_template_id']) {
			$collection_info['post_id'] = $options['kirki_template_id'];
		}
		if(isset($options['inside_symbol']) && $options['inside_symbol'] === true){
			$collection_info['post_id'] = $options['symbol_id'];
		}
		return $collection_info;
	}

	/**
	 * Generate custom code markup
	 *
	 * @param array $this_data single element block.
	 * @param array $attributes single element all attributes.
	 * @return string HTML markup.
	 */
	private function custom_code( $this_data, $attributes ) {
		$properties = $this_data['properties'];
		if ( isset( $properties['content'] ) ) {
			if ( isset( $properties['data-type'] ) && $properties['data-type'] === 'url' ) {
				return '<div ' . $attributes . '>
                  <iframe
                    src="' . $properties['content'] . '"
                    title="' . $this_data['id'] . '"
                    allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
                    style="width:100%;height:100%;"
                  ></iframe>
                </div>';
			} else {
				return '<div ' . $attributes . '>' . $properties['content'] . '</div>';
			}
		}
		return '';
	}

	/**
	 * Generate Map element markup
	 *
	 * @param array $this_data single element block.
	 * @param array $attributes single element all attributes.
	 * @return string HTML markup.
	 */
	private function map_element( $this_data, $attributes ) {
		$properties = isset( $this_data['properties']['map'] ) ? $this_data['properties']['map'] : false;
		if ( ! $properties ) {
			return '';
		}
		return '<div ' . $attributes . '></div>';
	}

	/**
	 * Generate Video element markup
	 *
	 * @param array $this_data single element block.
	 * @param array $attributes single element all attributes.
	 * @return string HTML markup.
	 */
	private function video_element( $this_data, $attributes, $options ) {
		$properties       = $this_data['properties'];
		$name             = $properties['attributes']['name'];
		$src              = $properties['attributes']['src'];
		$scale            = isset( $properties['scale'] ) ? $properties['scale'] : 'cover';
		$aspectRatio      = isset( $properties['aspectRatio'] ) ? $properties['aspectRatio'] : '16 / 9';
		$type             = $properties['attributes']['type'];
		$controls         = $properties['attributes']['controls'];
		$play_inline      = isset( $properties['attributes']['playInline'] ) ? $properties['attributes']['playInline'] : true;
		$duration         = isset( $properties['attributes']['duration'] ) ? $properties['attributes']['duration'] : 0;
		$start_time       = $properties['attributes']['startTime'];
		$end_time         = isset( $properties['attributes']['endTime'] ) ? $properties['attributes']['endTime'] : $duration;
		$span_attr_string = $this->getAllAttributes(
			$this_data,
			array(
				'class'      => true,
				'data-kirki' => true,
				'rest'       => false,
			),
		);
		$dynamic_content  = isset( $properties['dynamicContent'] ) ? $properties['dynamicContent'] : false;

		if ( isset( $this_data['properties']['attributes']['muted'] ) && $this_data['properties']['attributes']['muted'] === false ) {
			unset( $this_data['properties']['attributes']['muted'] );
		}

		$video_attr_string = $this->getAllAttributes(
			$this_data,
			array(
				'class'                 => false,
				'data-kirki'            => false,
				'src'                   => false,
				'autoPlay'              => false,
				'controls'              => false,
				'dataVideoPlayListener' => false,
				'rest'                  => true,
			),
		);

		if ( $play_inline ) {
			$video_attr_string .= ' playsinline';
		}

		$poster = '';
		if ( isset( $properties['thumbnail'], $properties['thumbnail']['status'] ) && $properties['thumbnail']['status'] ) {
			$poster = isset( $properties['thumbnail'], $properties['thumbnail']['url'] ) ? $properties['thumbnail']['url'] : null;
		}

		$video_src = '';
		if ( $dynamic_content ) {
			// TODO: Need to get dynamic course video or image url for tutor lms using hook.
			if ( isset( $options['itemType'] ) ) {
				if ( $options['itemType'] === 'post' ) {
					if ( $options['post']->{$dynamic_content['value']} ) {
						$video_obj = $options['post']->{$dynamic_content['value']};

						if ( isset( $video_obj['url'] ) ) {
							$video_src = $video_obj['url'];
						}
					} else {
						$video_obj = HelperFunctions::get_post_dynamic_content( $dynamic_content['value'], isset( $options['post'] ) ? $options['post'] : null );

						if ( isset( $video_obj['url'] ) ) {
							$video_src = $video_obj['url'];
						}
					}
				}
			} else {
				$video_obj = HelperFunctions::get_post_dynamic_content( $dynamic_content['value'], isset( $options['post'] ) ? $options['post'] : null );

				if ( isset( $video_obj['url'] ) ) {
					$video_src = $video_obj['url'];
				}
			}
		}

		// if no dynamic video src then check original source for fallback video url
		if ( ! $video_src && ! $src ) {
			return '';
		} else {
			$src = $video_src ? $video_src : $src;
		}

		$video_url_type = $this->video_type( $src );

		if ( $video_url_type === 'youtube' ) {
			$video_src = $this->get_youtube_embed_url( $src ) . '?controls=' . $controls . '&amp;start=' . $start_time . '&end=' . $end_time;
		} elseif ( $video_url_type === 'vimeo' ) {
			$video_src = $this->get_vimeo_embed_url( $src ) . '?controls=' . $controls . '&amp;start=' . $start_time . '&end=' . $end_time;
		} elseif ( $video_url_type === 'tiktok' ) {
			$video_src = $this->get_tiktok_embed_url( $src ) . '?controls=' . $controls . '&amp;start=' . $start_time . '&end=' . $end_time;
		} else {
			$video_src = $src . '#t=' . $start_time . ',' . $duration;
		}

		$html = '<span ' . $span_attr_string . '>';
		if ( $video_url_type === 'youtube' || $video_url_type === 'vimeo' || $video_url_type === 'tiktok' ) {
			$html .= '<iframe height="100%" width="100%" title="' . $name . '" src="' . $video_src . '" style="aspect-ratio: ' . $aspectRatio . ';" ></iframe>';
		} else {
			if ( isset( $properties['attributes']['lazy'] ) && $properties['attributes']['lazy'] ) {
				// `data-src` is used in `source` tag to lazy load the video using JS. Check JS preview script for videos.
				$html .= '<video' . $video_attr_string . ' style="object-fit: ' . $scale . '; aspect-ratio: ' . $aspectRatio . ';" poster="' . $poster . '">
				<source data-src="' . $video_src . '" type="' . $type . '"></source></video>';
			} else {
				$html .= '<video' . $video_attr_string . ' style="object-fit: ' . $scale . '; aspect-ratio: ' . $aspectRatio . ';" poster="' . $poster . '">
				<source src="' . $video_src . '" type="' . $type . '"></source></video>';
			}
		}
		$html .= '</span>';
		return $html;
	}

	/**
	 * Generate Video element markup
	 *
	 * @param array $this_data single element block.
	 * @param array $attributes single element all attributes.
	 * @return string HTML markup.
	 */
	private function radio_group( $this_data, $attributes ) {
		$properties = $this_data['properties'];
		$data       = $properties['data']['child'];
		$name       = $properties['attributes']['name'];

		$str = '<div ' . $attributes . '>';

		foreach ( $data as $key => $child ) {
			$attrs  = "type='radio' name='{$name}' value='{$child['value']}'";
			$attrs .= $child['checked'] ? ' checked' : '';

			$str .= '<label>
                  <input ' . $attrs . '/>
                  <span>' . $child['content'] . '</span>
                </label>';
		}
		$str .= '</div>';
		return $str;
	}

	/**
	 * Generate popup-body element markup
	 *
	 * @param array $this_data single element block.
	 * @param array $attributes single element all attributes.
	 * @return string HTML markup.
	 */
	private function popup_element( $this_data, $attributes, $options ) {
		$children_markup = $this->construct_children_markup( isset( $this_data['children'] ) ? $this_data['children'] : array(), $options );
		return '<div class="kirki-popup-body-wrapper"><div ' . $attributes . '>' . $children_markup . '</div></div>';
	}

	/**
	 * Recursively Generate menu items element markup
	 *
	 * @param array $submenus all submenus.
	 * @param int   $depth menu nesting info.
	 * @return string HTML markup.
	 */
	private function rec_gen_menu_items( $submenus, $depth ) {
		if ( count( $submenus ) === 0 ) {
			return '';
		}
		if ( $depth === 0 ) {
			$str = '<ul class="' . 'kirki-nav-menu">';
		} else {
			$str = '<ul class="' . 'kirki-element-submenu">';
		}
		$depth++;
		foreach ( $submenus as $key => $menu ) {
			$str .= '<li class="' . 'kirki-element-nav-item"><a class="' . 'kirki-link-element" href="' . $menu->url . '" target="' . $menu->target . '">' . $menu->title . '</a>' . $this->rec_gen_menu_items( $menu->submenus, $depth ) . '</li>';
		}
		$str .= '</ul>';
		return $str;
	}

	/**
	 * This method will add css value and unit
	 *
	 * @param array $value css value and unit pair.
	 * @return string 5px | auto.
	 */
	private function add_unit( $value ) {
		if ( isset( $value['unit'] ) && $value['unit'] !== 'auto' ) {
			return $value['value'] . $value['unit'];
		}
		return 'auto';
	}

	/**
	 * Generate Image element markup
	 *
	 * @param array $this_data single element block.
	 * @param array $attributes single element all attributes.
	 * @param array $options single element all options.
	 * @return string HTML markup.
	 */
	private function image_element( $this_data, $attributes, $options ) {
		$properties      = $this_data['properties'];
		$svg_outer_html  = isset( $properties['svgOuterHtml'] ) ? $properties['svgOuterHtml'] : false;
		$dynamic_content = isset( $properties['dynamicContent'] ) ? $properties['dynamicContent'] : false;
		$dynamic_alt     = isset( $properties['dynamicAlt'] ) ? $properties['dynamicAlt'] : false;

		$user_initials = false;

		$src = '';

		if ( $dynamic_content ) {
			$image_data = array();

			if ( $dynamic_content['type'] === 'reference' && isset( $options['post'], $options['post']->ID ) ) {
				$content_info = array(
					'collectionItem' => array(
						'ID' => $options['post']->ID,
					),
					'dynamicContent' => $dynamic_content,
				);

				$content    = apply_filters( 'kirki_dynamic_content', false, $content_info );
				$image_data = $content;
			} elseif ( $dynamic_content['type'] === 'gallery' ) {
				$content_info = array(
					'collectionItem' => array(
						'id'  => $options['gallery']['id'],
						'url' => $options['gallery']['url'],

					),
					'dynamicContent' => $dynamic_content,
				);

				$content = apply_filters( 'kirki_dynamic_content', false, $content_info );

				$image_data = $content;
			} elseif ( $dynamic_content['type'] === 'user' ) {
				$user_id    = isset( $options['user'], $options['user']['ID'] ) ? $options['user']['ID'] : null;
				$src        = HelperFunctions::get_user_dynamic_content( $dynamic_content['value'], $user_id, $dynamic_content['meta'] ?? '' );
				$image_data = array(
					'src' => $src,
				);
			} elseif ( isset( $options['itemType'] ) ) {
				if ( $options['itemType'] === 'post' ) {
					if ( isset( $options['post']->{$dynamic_content['value']} ) && $options['post']->{$dynamic_content['value']} ) {
						$image_data = $options['post']->{$dynamic_content['value']};
					} else {
						$image_data = HelperFunctions::get_post_dynamic_content( $dynamic_content['value'], isset( $options['post'] ) ? $options['post'] : null );
					}
				} elseif ( $options['itemType'] === 'comment' ) {
					if ( isset( $options['comment']->{$dynamic_content['value']} ) && $options['comment']->{$dynamic_content['value']} ) {
						$image_data = $options['comment']->{$dynamic_content['value']};
					}
				} elseif ( $options['itemType'] === 'user' ) {
					if ( isset( $options['user'], $options['user'][ $dynamic_content['value'] ] ) ) {
						$image_data = array(
							'src' => $options['user'][ $dynamic_content['value'] ],
						);
					}
				}
			} else {
					$post       = isset( $options['post'] ) ? $options['post'] : get_post( HelperFunctions::get_post_id_if_possible_from_url() );
					$image_data = HelperFunctions::get_post_dynamic_content( $dynamic_content['value'], $post, isset( $dynamic_content['meta'] ) ? $dynamic_content['meta'] : null );
				if ( is_string( $image_data ) ) {
					$image_data = array(
						'src' => $image_data,
					);
				}
			}

			if ( isset( $image_data['src'] ) ) {
				$src = $image_data['src'];
			}

			if ( isset( $image_data['wp_attachment_id'] ) ) {
				$properties['wp_attachment_id'] = $image_data['wp_attachment_id'];
			}
		}

		if ( $dynamic_content && $src ) {
			// replace src and alt.
			$attributes = preg_replace( array( '/src="([^"]+")/i' ), array( '' ), $attributes );
		} else {
			$src = isset( $properties['attributes']['src'] ) ? $properties['attributes']['src'] : '';
		}

		// set dynamic alt here
		if ( $dynamic_alt ) {
			$new_alt = Utils::getDynamicRichTextValue( $dynamic_alt, $options );

			// Update properties array for consistency
			$properties['attributes']['alt'] = $new_alt;

			// Replace alt attribute inside the HTML string
			$attributes = preg_replace(
				'/alt="[^"]*"/i',
				'alt="' . esc_attr( $new_alt ) . '"',
				$attributes
			);
		} elseif ( empty( $properties['attributes']['alt'] ) ) {
			// get WordPress attachment alt text if alt is empty
			if ( isset( $properties['wp_attachment_id'] ) && $properties['wp_attachment_id'] ) {
				$alt_text   = get_post_meta( $properties['wp_attachment_id'], '_wp_attachment_image_alt', true );
				$attributes = preg_replace( '/alt="([^"]*)"/i', 'alt="' . esc_attr( $alt_text ) . '"', $attributes );
			}
		}

		$srcset = null;
		if ( ! $dynamic_content && isset( $properties['wp_attachment_id'] ) && $properties['wp_attachment_id'] ) {
			$srcset      = wp_get_attachment_image_srcset( $properties['wp_attachment_id'] );
			$attributes .= $srcset ? ' srcset="' . $srcset . '"' : '';

			$sizes       = '';
			$a_meta_data = wp_get_attachment_metadata( $properties['wp_attachment_id'] );
			if ( $a_meta_data && isset( $a_meta_data['width'] ) ) {
				$width       = $a_meta_data['width'];
				$sizes       = '(max-width: ' . $width . 'px) 100vw, ' . $width . 'px';
				$attributes .= $sizes ? ' sizes="' . $sizes . '"' : '';
			}
		}

		if ( ( isset( $properties['load'] ) && $properties['load'] !== 'auto' ) || ! isset( $properties['load'] ) ) {
			$attributes .= isset( $properties['load'] ) ? ' loading="' . $properties['load'] . '"' : ' loading="lazy"';
		}

		if ( isset( $properties['width'] ) ) {
			$attributes .= ' width="' . $this->add_unit( $properties['width'] ) . '"';

		}
		if ( isset( $properties['height'] ) ) {
			$attributes .= ' height="' . $this->add_unit( $properties['height'] ) . '"';
		}

		if ( ! $src ) {
			return '';
		}

		$str = '';

		if ( $svg_outer_html ) {
			$str .= '<img ' . $attributes . ' src="' . $src . '"/>
               <span>' . $svg_outer_html . '</span>';
		} else {
			$str .= '<img ' . $attributes . ' src="' . $src . '"/>';
		}

		return $str;
	}

	/**
	 * Get video type from url
	 *
	 * @param string $url single element block.
	 * @return string|bool video url type.
	 */
	private function video_type( $url ) {
		if ( strpos( $url, 'youtube' ) > 0 || strpos( $url, 'youtu.be' ) > 0 ) {
			return 'youtube';
		} elseif ( strpos( $url, 'vimeo' ) > 0 ) {
			return 'vimeo';
		} elseif ( strpos( $url, 'tiktok' ) > 0 ) {
			return 'tiktok';
		} else {
			return false;
		}
	}

	/**
	 * Get video type from url
	 *
	 * @param string $url single element block.
	 * @return string youtube url type.
	 */
	private function get_youtube_embed_url( $url ) {
		preg_match( '%(?:youtube(?:-nocookie)?\.com/(?:[^/]+/.+/|(?:v|e(?:mbed)?)/|.*[?&]v=)|youtu\.be/)([^"&?/ ]{11})%i', $url, $match );
		return isset( $match[1] ) ? 'https://www.youtube.com/embed/' . $match[1] : '#';
	}

	private function get_vimeo_embed_url( $url ) {
		preg_match( '/vimeo\.com\/(?:.*\/)?(\d+)/', $url, $matches );
		return isset( $matches[1] ) ? 'https://player.vimeo.com/video/' . $matches[1] : '#';
	}

	private function get_tiktok_embed_url( $url ) {
		preg_match( '/tiktok\.com\/(?:@[\w.-]+\/)?video\/(\d+)/', $url, $matches );
		return isset( $matches[1] ) ? 'https://www.tiktok.com/embed/' . $matches[1] : '#';
	}

	/**
	 * Generate symbol markup
	 *
	 * @param array $this_data single element block.
	 * @param array $attributes single element all attributes.
	 * @return string HTML markup.
	 */
	private function generate_symbol_html( $this_data, $attributes, $options = array() ) {
		$properties        = $this_data['properties'];
		$symbol_id         = $properties['symbolId'];
		$symbolElementProp = isset( $properties['symbolElProps'] ) ? $properties['symbolElProps'] : false;
		$symbol            = Symbol::get_single_symbol( $symbol_id, true, false, $symbolElementProp );

		if ( ! $symbol ) {
			return '';
		}

		$symbol_data = $symbol['symbolData'];
		if ( ! $symbol_data || ! isset( $symbol_data['data'] ) ) {
			return '';
		}
		$options['symbol_id'] = $symbol_id;
		$options['inside_symbol'] = true;

		$s           = HelperFunctions::rec_update_data_id_then_return_new_html( $symbol_data['data'], $symbol_data['styleBlocks'], $symbol_data['root'], $options );
		$fonts_links = '';
		if ( isset( $symbol_data['customFonts'] ) ) {
			foreach ( $symbol_data['customFonts'] as $key => $f ) {
				if ( isset( $f['fontUrl'] ) ) {
					$fonts_links .= HelperFunctions::getFontsHTMLMarkup( $f );
				}
			}
		}
		return '<div ' . $attributes . '>' . $fonts_links . $s . '</div>';
	}

	/**
	 * Get html template.
	 *
	 * @param string $template template file name.
	 * @param array  $vars if extra variable needs inside template file.
	 * @return string $message
	 */
	private function get_template( $template, $vars ) {
		ob_start();
		include __DIR__ . "/templates/$template.view.php";
		$message = ob_get_contents();
		ob_end_clean();
		return $message;
	}

	/**
	 * Generate File upload element markup
	 *
	 * @param array $this_data single element block.
	 * @param array $attributes single element all attributes.
	 * @param array $options single element all options.
	 * @return string HTML markup.
	 */
	private function file_upload_element( $this_data, $attributes, $options ) {
		$tag       = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
		$data_attr = isset( $this_data['properties']['attributes'] ) ? $this_data['properties']['attributes'] : array();
		$options   = array_merge(
			$options,
			array(
				'file_upload' => array(
					'name'        => isset( $data_attr['name'] ) ? $data_attr['name'] : '',
					'accept'      => isset( $data_attr['accept'] ) ? $data_attr['accept'] : '',
					'required'    => isset( $data_attr['required'] ) ? $data_attr['required'] : '',
					'maxFileSize' => isset( $this_data['properties']['maxFileSize'] ) ? $this_data['properties']['maxFileSize'] : 2,
				),
			)
		);

		$attributes = $this->getAllAttributes(
			$this_data,
			array(
				'name'     => false,
				'accept'   => false,
				'required' => false,
				'rest'     => true,
			),
		);

		$children_markup = $this->construct_children_markup( isset( $this_data['children'] ) ? $this_data['children'] : array(), $options );
		return "<$tag $attributes>
						$children_markup
					</$tag>";
	}

	/**
	 * Generate File input threshold text element markup
	 *
	 * @param array $this_data single element block.
	 * @param array $attributes single element all attributes.
	 * @param array $options single element all options.
	 * @return string HTML markup.
	 */

	private function file_upload_threshold_text( $this_data, $attributes, $options ) {
		$tag           = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'span';
		$max_file_size = isset( $options['file_upload']['maxFileSize'] ) ? $options['file_upload']['maxFileSize'] : 2;

		return "<$tag $attributes>Max file size " . $max_file_size . "MB.</$tag>";
	}

	/**
	 * Generate File input element markup
	 *
	 * @param array $this_data single element block.
	 * @param array $attributes single element all attributes.
	 * @param array $options single element all options.
	 * @return string HTML markup.
	 */
	private function file_input_element( $this_data, $attributes, $options ) {
		$tag      = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
		$children = $this_data['children'] ?? array();
		$markup   = '';

		$name          = isset( $options['file_upload']['name'] ) ? $options['file_upload']['name'] : '';
		$accept        = isset( $options['file_upload']['accept'] ) ? $options['file_upload']['accept'] : '';
		$required      = isset( $options['file_upload']['required'] ) ? $options['file_upload']['required'] : '';
		$max_file_size = isset( $options['file_upload']['maxFileSize'] ) ? $options['file_upload']['maxFileSize'] : 2;

		foreach ( $children as $child ) {
			$markup .= $this->recGenHTML( $child, $options );
		}

		return "<$tag $attributes>
						$markup
						<input
							type=\"file\"
							readonly
							style=\"display: none;\"
							name=\"$name\"
							accept=\"$accept\"
							required=\"$required\"
							kirki-max_file_size=$max_file_size
							/>
						</$tag>";
	}

	private function slider_nav_element( $this_data, $attributes, $options ) {
		$tag                 = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
		$collection          = isset( $options['collection'] ) ? $options['collection'] : array();
		$itemType            = isset( $options['itemType'] ) ? $options['itemType'] : 'post';
		$slider_nav_item_id  = isset( $this_data['children'][0] ) ? $this_data['children'][0] : '';
		$slider_nav_children = isset( $this_data['children'] ) ? $this_data['children'] : array();
		$slider_mode         = $options['slider_mode'] ?? 'manual';
		$page_no             = isset( $options['page_no'] ) ? (int) $options['page_no'] : 1;

		$children = array();

		if ( $slider_mode === 'manual' ) {
			foreach ( $slider_nav_children as $key => $child_id ) {
				$children[] = $this->recGenHTML( $child_id, $options );
			}
		} else { // dynamic
			if ( empty( $collection ) || ! $slider_nav_item_id ) {
				return '';
			}

			$items_per_page = isset( $options['items_per_page'] ) ? (int) $options['items_per_page'] : count( $collection );

			$start           = ( $page_no - 1 ) * $items_per_page;
			$items_to_render = array_slice( $collection, $start, $items_per_page );

			foreach ( $items_to_render as $key => $collection_item ) {
				$item_index = HelperFunctions::get_current_item_index( $key + 1, $options );

				$merged_options = array_merge(
					$options,
					array(
						'itemType'   => $itemType,
						$itemType    => $collection_item,
						'item_index' => $item_index,
						'nav_index'  => $start + $key,
						'is_active'  => $key === 0,
					)
				);

				$children[] = HelperFunctions::rec_update_data_id_then_return_new_html( $this->data, $this->style_blocks, $slider_nav_item_id, $merged_options, ( $key === 0 ) );
			}
		}

		return $this->get_template(
			'pagination-item',
			array(
				'attributes'   => $attributes,
				'children'     => $children,
				'current_page' => 1,
				'page_number'  => $page_no,
				'tag'          => $tag,
			)
		);
	}

	private function tabs_element( $this_data, $attributes, $options ) {
		$tag      = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
		$children = $this_data['children'] ?? array();
		$markup   = '';

		foreach ( $children as $child ) {
			$merged_options = array_merge(
					$options,
					array(
						'active_tab_index' => isset($this_data['properties'],$this_data['properties']['active_tab']) ? $this_data['properties']['active_tab'] : 0,
					)
				);

			$markup .= $this->recGenHTML( $child, $merged_options );
		}

		return "<$tag $attributes>
						$markup
					</$tag>";
	}

	private function tab_element( $this_data, $attributes, $options ) {
		$tag      = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
		$children = $this_data['children'] ?? array();
		$markup   = '';

		$active_tab_index = isset( $options['active_tab_index'] ) ? $options['active_tab_index'] : 0;
		$item_index       = isset( $options['item_index'] ) ? $options['item_index'] : 0;

		if ( $active_tab_index === $item_index ) {
			// Add kirki-current-tab class to attributes
			if ( preg_match( '/class="([^"]*)"/', $attributes, $matches ) ) {
				// Class attribute exists, append to it
				$existing_classes = $matches[1];
				$new_classes      = trim( $existing_classes . ' kirki-current-tab' );
				$attributes       = preg_replace(
					'/class="[^"]*"/',
					'class="' . esc_attr( $new_classes ) . '"',
					$attributes
				);
			} else {
				// No class attribute, add it
				$attributes .= ' class="kirki-current-tab"';
			}
		}

		// foreach ( $children as $child ) {
		// 	$markup .= $this->recGenHTML( $child, $options );
		// }
		$markup = $this->get_child_content_or_childrens( $this_data, $options );
		return "<$tag $attributes>
						$markup
					</$tag>";
	}

	private function tab_pane_element( $this_data, $attributes, $options ) {
		$tag      = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
		$children = $this_data['children'] ?? array();
		$markup   = '';

		$active_tab_index = isset( $options['active_tab_index'] ) ? $options['active_tab_index'] : 0;
		$item_index       = isset( $options['item_index'] ) ? $options['item_index'] : 0;

		if ( $active_tab_index === $item_index ) {
			// Add kirki-tab-active class to attributes
			if ( preg_match( '/class="([^"]*)"/', $attributes, $matches ) ) {
				// Class attribute exists, append to it
				$existing_classes = $matches[1];
				$new_classes      = trim( $existing_classes . ' kirki-tab-active' );
				$attributes       = preg_replace(
					'/class="[^"]*"/',
					'class="' . esc_attr( $new_classes ) . '"',
					$attributes
				);
			} else {
				// No class attribute, add it
				$attributes .= ' class="kirki-tab-active"';
			}
		}

		$markup = $this->get_child_content_or_childrens( $this_data, $options );
		return "<$tag $attributes>
						$markup
					</$tag>";
	}

	private function tab_menu_and_content_element( $this_data, $attributes, $options ) {
		$tag      = isset( $this_data['properties']['tag'] ) ? $this_data['properties']['tag'] : 'div';
		$children = $this_data['children'] ?? array();
		$markup   = '';

		$markup = $this->get_child_content_or_childrens( $this_data, $options );
		if($this_data['name'] === 'tab_menu'){
			$attributes .= ' data-kirki_tab="tab_menu"';
		}else{
			$attributes .= ' data-kirki_tab="tab_content"';
		}
		return "<$tag $attributes>
						$markup
					</$tag>";
	}

}