<?php
/**
 * Storzen v1.2.2 — Archive / Shop Page Toolbar Widgets
 *
 * Three standalone widgets for the Archive / Shop page toolbar area:
 *
 *  • Storzen_Archive_Ordering_Widget      — Sort-by dropdown (price, popularity,
 *                                           newest, rating). Wraps WooCommerce's
 *                                           native woocommerce_catalog_ordering().
 *
 *  • Storzen_Archive_Result_Count_Widget  — "Showing 1–12 of 36 results" text.
 *                                           Wraps woocommerce_result_count().
 *
 *  • Storzen_Archive_Title_Widget         — Dynamic archive title: category name,
 *                                           "Shop", search term, or tag name.
 *                                           Uses woocommerce_page_title() and
 *                                           accepts a static fallback.
 *
 * INSTALLATION:
 *   Copy to: storzen/elementor/widgets/class-storzen-style-archive-toolbar.php
 *   Apply the patch documented in the patch instructions file.
 *
 * Why these wrap the native WC functions:
 *   Using woocommerce_catalog_ordering(), woocommerce_result_count(), and
 *   woocommerce_page_title() means every theme hook, WC filter, and WPML /
 *   Polylang translation registered by third-party plugins continues to work
 *   without any duplication. We are giving the page-builder positional freedom
 *   over WC output — not reimplementing it.
 *
 * @package storzen
 * @since   1.2.2
 */

namespace Elementor;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

// ─────────────────────────────────────────────────────────────────────────────
// Shared helper trait for archive-context widgets
// ─────────────────────────────────────────────────────────────────────────────

/**
 * Helpers shared by all three archive toolbar widgets.
 *
 * @since 1.2.2
 */
trait Storzen_Archive_Widget_Helpers {

	/**
	 * True when WooCommerce is active and at least the wc_get_loop_prop()
	 * function exists (WC 3.3+).
	 */
	protected function szp_wc_ready() {
		return function_exists( 'WC' ) && function_exists( 'wc_get_loop_prop' );
	}

	/**
	 * True when the current request is an archive / shop context OR when we
	 * are inside the Elementor editor / preview iframe.
	 *
	 * In the editor, template context is not a real shop page, so
	 * is_woocommerce() returns false. We always allow render in edit mode so
	 * the designer can work.
	 */
	protected function szp_is_archive_or_editor() {
		// Real archive / shop / search context.
		if ( function_exists( 'is_woocommerce' ) && ( is_woocommerce() || is_shop() ) ) {
			return true;
		}

		$pl = \Elementor\Plugin::$instance;

		// Elementor editor.
		if ( ! empty( $pl->editor )
			&& method_exists( $pl->editor, 'is_edit_mode' )
			&& $pl->editor->is_edit_mode() ) {
			return true;
		}

		// Elementor preview iframe.
		if ( ! empty( $pl->preview )
			&& method_exists( $pl->preview, 'is_preview_mode' )
			&& $pl->preview->is_preview_mode() ) {
			return true;
		}

		return false;
	}

	/**
	 * Render an editor-only placeholder block.
	 *
	 * @param string $label Human-readable description.
	 */
	protected function szp_archive_placeholder( $label ) {
		printf(
			'<div class="szp-archive-placeholder" style="padding:14px 16px;border:1px dashed #d0d0d0;border-radius:6px;background:#f9f9f9;font-size:13px;color:#666;line-height:1.5;">%s</div>',
			esc_html( $label )
		);
	}
}


// ─────────────────────────────────────────────────────────────────────────────
// Widget 1: Archive Ordering (Sort By)
// ─────────────────────────────────────────────────────────────────────────────

/**
 * WooCommerce catalog sort-by dropdown widget.
 *
 * Renders the native WooCommerce sort-by form via woocommerce_catalog_ordering()
 * so all WC hooks, theme template overrides, and third-party order options (e.g.
 * YITH, WooCommerce Extra Product Sorting Options) work automatically.
 *
 * Style controls let the designer adjust the select width, border, typography,
 * and layout alignment without touching the WC form markup.
 *
 * Toggle key:  archive_ordering
 * Category:    storzen-archive
 *
 * @since 1.2.2
 */
class Storzen_Archive_Ordering_Widget extends Widget_Base {

	use Storzen_Archive_Widget_Helpers;

	// ── Identity ──────────────────────────────────────────────────────────────

	public function get_name() {
		return 'storzen-archive-ordering';
	}

	public function get_title() {
		return esc_html__( 'Archive Ordering', 'storzen' );
	}

	public function get_icon() {
		return 'eicon-sort-amount-asc';
	}

	public function get_categories() {
		return array( 'storzen-archive' );
	}

	public function get_keywords() {
		return array( 'sort', 'order', 'filter', 'archive', 'shop', 'catalog', 'storzen' );
	}

	// ── Controls ──────────────────────────────────────────────────────────────

	protected function register_controls() {

		// ── Content tab ───────────────────────────────────────────────────────

		$this->start_controls_section(
			'section_ordering_content',
			array(
				'label' => esc_html__( 'Ordering', 'storzen' ),
				'tab'   => Controls_Manager::TAB_CONTENT,
			)
		);

		$this->add_control(
			'ordering_info',
			array(
				'type'            => Controls_Manager::RAW_HTML,
				'raw'             => sprintf(
					'<div style="font-size:12px;line-height:1.6;color:#666;background:#f0f6ff;padding:10px 12px;border-radius:4px;border-left:3px solid #5b9bd5;">%s</div>',
					esc_html__( 'Uses WooCommerce\'s native woocommerce_catalog_ordering() function. Sort options are controlled in WooCommerce → Settings → Products. Theme template overrides (woocommerce/loop/orderby.php) apply automatically.', 'storzen' )
				),
				'content_classes' => 'elementor-panel-alert',
			)
		);

		$this->add_responsive_control(
			'align',
			array(
				'label'     => esc_html__( 'Alignment', 'storzen' ),
				'type'      => Controls_Manager::CHOOSE,
				'options'   => array(
					'flex-start' => array( 'title' => esc_html__( 'Left', 'storzen' ),   'icon' => 'eicon-text-align-left' ),
					'center'     => array( 'title' => esc_html__( 'Center', 'storzen' ), 'icon' => 'eicon-text-align-center' ),
					'flex-end'   => array( 'title' => esc_html__( 'Right', 'storzen' ),  'icon' => 'eicon-text-align-right' ),
				),
				'default'   => 'flex-end',
				'selectors' => array(
					'{{WRAPPER}} .sz-archive-ordering' => 'justify-content: {{VALUE}};',
				),
			)
		);

		$this->end_controls_section();

		// ── Style tab — Select ────────────────────────────────────────────────

		$this->start_controls_section(
			'section_ordering_style',
			array(
				'label' => esc_html__( 'Select Dropdown', 'storzen' ),
				'tab'   => Controls_Manager::TAB_STYLE,
			)
		);

		$this->add_responsive_control(
			'select_width',
			array(
				'label'      => esc_html__( 'Width', 'storzen' ),
				'type'       => Controls_Manager::SLIDER,
				'size_units' => array( 'px', '%' ),
				'range'      => array(
					'px' => array( 'min' => 100, 'max' => 500 ),
					'%'  => array( 'min' => 10,  'max' => 100 ),
				),
				'default'    => array( 'unit' => 'px', 'size' => 200 ),
				'selectors'  => array(
					'{{WRAPPER}} .sz-archive-ordering select,
					 {{WRAPPER}} .sz-archive-ordering .orderby' => 'width: {{SIZE}}{{UNIT}};',
				),
			)
		);

		$this->add_group_control(
			Group_Control_Typography::get_type(),
			array(
				'name'     => 'select_typography',
				'selector' => '{{WRAPPER}} .sz-archive-ordering select,
				               {{WRAPPER}} .sz-archive-ordering .orderby',
			)
		);

		$this->add_control(
			'select_text_color',
			array(
				'label'     => esc_html__( 'Text Color', 'storzen' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '#1f2937',
				'selectors' => array(
					'{{WRAPPER}} .sz-archive-ordering select,
					 {{WRAPPER}} .sz-archive-ordering .orderby' => 'color: {{VALUE}};',
				),
			)
		);

		$this->add_control(
			'select_bg_color',
			array(
				'label'     => esc_html__( 'Background', 'storzen' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '#ffffff',
				'selectors' => array(
					'{{WRAPPER}} .sz-archive-ordering select,
					 {{WRAPPER}} .sz-archive-ordering .orderby' => 'background-color: {{VALUE}};',
				),
			)
		);

		$this->add_group_control(
			Group_Control_Border::get_type(),
			array(
				'name'     => 'select_border',
				'selector' => '{{WRAPPER}} .sz-archive-ordering select,
				               {{WRAPPER}} .sz-archive-ordering .orderby',
				'fields_options' => array(
					'border' => array( 'default' => 'solid' ),
					'width'  => array( 'default' => array( 'top' => '1', 'right' => '1', 'bottom' => '1', 'left' => '1', 'unit' => 'px' ) ),
					'color'  => array( 'default' => '#e5e7eb' ),
				),
			)
		);

		$this->add_control(
			'select_border_radius',
			array(
				'label'      => esc_html__( 'Border Radius', 'storzen' ),
				'type'       => Controls_Manager::SLIDER,
				'size_units' => array( 'px', '%' ),
				'range'      => array( 'px' => array( 'min' => 0, 'max' => 30 ) ),
				'default'    => array( 'unit' => 'px', 'size' => 4 ),
				'selectors'  => array(
					'{{WRAPPER}} .sz-archive-ordering select,
					 {{WRAPPER}} .sz-archive-ordering .orderby' => 'border-radius: {{SIZE}}{{UNIT}};',
				),
			)
		);

		$this->add_responsive_control(
			'select_padding',
			array(
				'label'      => esc_html__( 'Padding', 'storzen' ),
				'type'       => Controls_Manager::DIMENSIONS,
				'size_units' => array( 'px', 'em' ),
				'default'    => array(
					'top'    => '8',
					'right'  => '32',
					'bottom' => '8',
					'left'   => '12',
					'unit'   => 'px',
				),
				'selectors'  => array(
					'{{WRAPPER}} .sz-archive-ordering select,
					 {{WRAPPER}} .sz-archive-ordering .orderby' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
				),
			)
		);

		$this->end_controls_section();
	}

	// ── Render ────────────────────────────────────────────────────────────────

	protected function render() {

		if ( ! $this->szp_wc_ready() ) {
			$this->szp_archive_placeholder( esc_html__( 'Archive Ordering — requires WooCommerce.', 'storzen' ) );
			return;
		}

		if ( ! $this->szp_is_archive_or_editor() ) {
			return; // Silently skip on non-archive pages at runtime.
		}

		// Ensure the WC loop properties are set for ordering to work.
		wc_maybe_define_constant( 'WOOCOMMERCE_SHOP', true );

		echo '<div class="sz-archive-ordering woocommerce">';

		if ( function_exists( 'woocommerce_catalog_ordering' ) ) {
			/*
			 * woocommerce_catalog_ordering() checks wc_get_loop_prop('is_shortcode')
			 * and a WC option ('woocommerce_enable_catalog_ordering'). Both must be
			 * truthy. We temporarily set the loop prop so the function doesn't bail.
			 */
			$restore = wc_get_loop_prop( 'is_shortcode' );
			wc_set_loop_prop( 'is_shortcode', false );

			woocommerce_catalog_ordering();

			wc_set_loop_prop( 'is_shortcode', $restore );
		} else {
			// Fallback: plain select if WC function not available.
			$this->render_fallback_select();
		}

		echo '</div><!-- .sz-archive-ordering -->';
	}

	/**
	 * Minimal fallback sort-by select (used only when woocommerce_catalog_ordering
	 * is not available — very rare; defensive coding only).
	 */
	private function render_fallback_select() {
		$current  = isset( $_GET['orderby'] ) ? sanitize_text_field( wp_unslash( $_GET['orderby'] ) ) : apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby', 'menu_order' ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$base_url = remove_query_arg( 'orderby', wc_get_current_shop_page_url() );

		// These labels intentionally reuse WooCommerce's own translated strings via the
		// 'woocommerce' text domain, so they follow the store's language exactly like the
		// native ordering dropdown. Re-domaining them to 'storzen' would break that reuse.
		// phpcs:disable WordPress.WP.I18n.TextDomainMismatch
		$options = apply_filters(
			'woocommerce_catalog_orderby',
			array(
				'menu_order' => esc_html__( 'Default sorting', 'woocommerce' ),
				'popularity' => esc_html__( 'Sort by popularity', 'woocommerce' ),
				'rating'     => esc_html__( 'Sort by average rating', 'woocommerce' ),
				'date'       => esc_html__( 'Sort by latest', 'woocommerce' ),
				'price'      => esc_html__( 'Sort by price: low to high', 'woocommerce' ),
				'price-desc' => esc_html__( 'Sort by price: high to low', 'woocommerce' ),
			)
		);
		// phpcs:enable WordPress.WP.I18n.TextDomainMismatch

		echo '<form class="woocommerce-ordering" method="get">';
		printf(
			'<select name="orderby" class="orderby" aria-label="%s">',
			esc_attr__( 'Shop order', 'woocommerce' ) // phpcs:ignore WordPress.WP.I18n.TextDomainMismatch
		);

		foreach ( $options as $id => $label ) {
			printf(
				'<option value="%s"%s>%s</option>',
				esc_attr( $id ),
				selected( $current, $id, false ),
				esc_html( $label )
			);
		}

		echo '</select>';

		// Carry forward existing query vars.
		foreach ( $_GET as $key => $val ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			if ( 'orderby' === $key || 'submit' === $key ) {
				continue;
			}
			printf(
				'<input type="hidden" name="%s" value="%s" />',
				esc_attr( $key ),
				esc_attr( sanitize_text_field( wp_unslash( $val ) ) )
			);
		}

		echo '</form>';
	}
}


// ─────────────────────────────────────────────────────────────────────────────
// Widget 2: Archive Result Count
// ─────────────────────────────────────────────────────────────────────────────

/**
 * WooCommerce result count display widget.
 *
 * Renders the native WooCommerce result count string via woocommerce_result_count()
 * ("Showing 1–12 of 36 results"). The WC function respects the current pagination,
 * active filters, and the woocommerce_result_count_args filter.
 *
 * Toggle key:  archive_result_count
 * Category:    storzen-archive
 *
 * @since 1.2.2
 */
class Storzen_Archive_Result_Count_Widget extends Widget_Base {

	use Storzen_Archive_Widget_Helpers;

	// ── Identity ──────────────────────────────────────────────────────────────

	public function get_name() {
		return 'storzen-archive-result-count';
	}

	public function get_title() {
		return esc_html__( 'Archive Result Count', 'storzen' );
	}

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

	public function get_categories() {
		return array( 'storzen-archive' );
	}

	public function get_keywords() {
		return array( 'result', 'count', 'showing', 'archive', 'shop', 'storzen' );
	}

	// ── Controls ──────────────────────────────────────────────────────────────

	protected function register_controls() {

		// ── Content tab ───────────────────────────────────────────────────────

		$this->start_controls_section(
			'section_count_content',
			array(
				'label' => esc_html__( 'Result Count', 'storzen' ),
				'tab'   => Controls_Manager::TAB_CONTENT,
			)
		);

		$this->add_control(
			'count_info',
			array(
				'type' => Controls_Manager::RAW_HTML,
				'raw'  => sprintf(
					'<div style="font-size:12px;line-height:1.6;color:#666;background:#f0f6ff;padding:10px 12px;border-radius:4px;border-left:3px solid #5b9bd5;">%s</div>',
					esc_html__( 'Uses WooCommerce\'s native woocommerce_result_count() function. The string is automatically localised and respects the current page, products-per-page setting, and active filters. Customize the string with the woocommerce_result_count_args filter.', 'storzen' )
				),
			)
		);

		$this->add_responsive_control(
			'align',
			array(
				'label'     => esc_html__( 'Alignment', 'storzen' ),
				'type'      => Controls_Manager::CHOOSE,
				'options'   => array(
					'left'   => array( 'title' => esc_html__( 'Left', 'storzen' ),   'icon' => 'eicon-text-align-left' ),
					'center' => array( 'title' => esc_html__( 'Center', 'storzen' ), 'icon' => 'eicon-text-align-center' ),
					'right'  => array( 'title' => esc_html__( 'Right', 'storzen' ),  'icon' => 'eicon-text-align-right' ),
				),
				'default'   => 'left',
				'selectors' => array(
					'{{WRAPPER}} .sz-archive-result-count' => 'text-align: {{VALUE}};',
				),
			)
		);

		$this->end_controls_section();

		// ── Style tab ─────────────────────────────────────────────────────────

		$this->start_controls_section(
			'section_count_style',
			array(
				'label' => esc_html__( 'Count Text', 'storzen' ),
				'tab'   => Controls_Manager::TAB_STYLE,
			)
		);

		$this->add_control(
			'text_color',
			array(
				'label'     => esc_html__( 'Color', 'storzen' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '#6b7280',
				'selectors' => array(
					'{{WRAPPER}} .sz-archive-result-count,
					 {{WRAPPER}} .sz-archive-result-count p,
					 {{WRAPPER}} .woocommerce-result-count' => 'color: {{VALUE}};',
				),
			)
		);

		$this->add_group_control(
			Group_Control_Typography::get_type(),
			array(
				'name'     => 'count_typography',
				'selector' => '{{WRAPPER}} .sz-archive-result-count,
				               {{WRAPPER}} .sz-archive-result-count p,
				               {{WRAPPER}} .woocommerce-result-count',
			)
		);

		$this->add_responsive_control(
			'count_margin',
			array(
				'label'      => esc_html__( 'Margin', 'storzen' ),
				'type'       => Controls_Manager::DIMENSIONS,
				'size_units' => array( 'px', 'em' ),
				'selectors'  => array(
					'{{WRAPPER}} .sz-archive-result-count' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
				),
			)
		);

		$this->end_controls_section();
	}

	// ── Render ────────────────────────────────────────────────────────────────

	protected function render() {

		if ( ! $this->szp_wc_ready() ) {
			$this->szp_archive_placeholder( esc_html__( 'Archive Result Count — requires WooCommerce.', 'storzen' ) );
			return;
		}

		if ( ! $this->szp_is_archive_or_editor() ) {
			return;
		}

		echo '<div class="sz-archive-result-count woocommerce">';

		if ( function_exists( 'woocommerce_result_count' ) ) {
			/*
			 * woocommerce_result_count() internally calls wc_get_loop_prop().
			 * If the loop has not been initialised (e.g. pure Elementor template
			 * page without the Archive Grid widget), loop props may be zero.
			 * We set sensible defaults so the count string renders correctly.
			 */
			$total   = wc_get_loop_prop( 'total' );
			$per_pag = wc_get_loop_prop( 'per_page' );
			$paged   = wc_get_loop_prop( 'current_page' );

			// Initialise props from the global WP_Query when not already set.
			if ( ! $total && ! is_null( $GLOBALS['wp_query'] ?? null ) ) {
				$q = $GLOBALS['wp_query'];
				wc_set_loop_prop( 'total',        (int) $q->found_posts );
				wc_set_loop_prop( 'per_page',     (int) $q->get( 'posts_per_page' ) );
				wc_set_loop_prop( 'current_page', max( 1, (int) $q->get( 'paged' ) ) );
			}

			woocommerce_result_count();
		}

		echo '</div><!-- .sz-archive-result-count -->';
	}
}


// ─────────────────────────────────────────────────────────────────────────────
// Widget 3: Archive Title
// ─────────────────────────────────────────────────────────────────────────────

/**
 * Dynamic archive page title widget.
 *
 * Renders the correct page title for any WooCommerce archive context:
 *   • Product category  → category name (with optional description strip)
 *   • Product tag       → tag name
 *   • Search results    → 'Search results: "query"'
 *   • Main shop         → "Shop" (or the WC shop page title)
 *
 * Uses woocommerce_page_title() which respects the
 * woocommerce_page_title filter — so third-party plugins (e.g. Yoast,
 * WC Brands) can modify the output without any extra work here.
 *
 * A static fallback text can be supplied for use on non-archive pages
 * (e.g. when the widget is placed on a custom landing page).
 *
 * Toggle key:  archive_title
 * Category:    storzen-archive
 *
 * @since 1.2.2
 */
class Storzen_Archive_Title_Widget extends Widget_Base {

	use Storzen_Archive_Widget_Helpers;

	// ── Identity ──────────────────────────────────────────────────────────────

	public function get_name() {
		return 'storzen-archive-title';
	}

	public function get_title() {
		return esc_html__( 'Archive Title', 'storzen' );
	}

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

	public function get_categories() {
		return array( 'storzen-archive' );
	}

	public function get_keywords() {
		return array( 'title', 'archive', 'shop', 'category', 'heading', 'storzen' );
	}

	// ── Controls ──────────────────────────────────────────────────────────────

	protected function register_controls() {

		// ── Content tab ───────────────────────────────────────────────────────

		$this->start_controls_section(
			'section_title_content',
			array(
				'label' => esc_html__( 'Archive Title', 'storzen' ),
				'tab'   => Controls_Manager::TAB_CONTENT,
			)
		);

		$this->add_control(
			'title_source',
			array(
				'label'       => esc_html__( 'Title Source', 'storzen' ),
				'type'        => Controls_Manager::SELECT,
				'default'     => 'dynamic',
				'options'     => array(
					'dynamic' => esc_html__( 'Dynamic (woocommerce_page_title)', 'storzen' ),
					'static'  => esc_html__( 'Custom / Static', 'storzen' ),
				),
				'description' => esc_html__( 'Dynamic: outputs the WooCommerce page title for the current archive (category name, tag name, search string, or "Shop"). Static: always shows the text you enter below.', 'storzen' ),
			)
		);

		$this->add_control(
			'static_title',
			array(
				'label'       => esc_html__( 'Custom Title', 'storzen' ),
				'type'        => Controls_Manager::TEXT,
				'default'     => esc_html__( 'Shop', 'storzen' ),
				'placeholder' => esc_html__( 'Enter title…', 'storzen' ),
				'label_block' => true,
				'condition'   => array( 'title_source' => 'static' ),
			)
		);

		$this->add_control(
			'fallback_title',
			array(
				'label'       => esc_html__( 'Fallback Title', 'storzen' ),
				'type'        => Controls_Manager::TEXT,
				'default'     => esc_html__( 'Shop', 'storzen' ),
				'placeholder' => esc_html__( 'Shown when dynamic title is empty…', 'storzen' ),
				'label_block' => true,
				'condition'   => array( 'title_source' => 'dynamic' ),
				'description' => esc_html__( 'Shown when the dynamic title resolves to an empty string (e.g. on a non-archive page).', 'storzen' ),
			)
		);

		$this->add_control(
			'tag',
			array(
				'label'   => esc_html__( 'HTML Tag', 'storzen' ),
				'type'    => Controls_Manager::SELECT,
				'default' => 'h1',
				'options' => array(
					'h1'   => 'H1',
					'h2'   => 'H2',
					'h3'   => 'H3',
					'h4'   => 'H4',
					'h5'   => 'H5',
					'h6'   => 'H6',
					'div'  => 'div',
					'span' => 'span',
					'p'    => 'p',
				),
			)
		);

		$this->add_responsive_control(
			'align',
			array(
				'label'     => esc_html__( 'Alignment', 'storzen' ),
				'type'      => Controls_Manager::CHOOSE,
				'options'   => array(
					'left'   => array( 'title' => esc_html__( 'Left', 'storzen' ),   'icon' => 'eicon-text-align-left' ),
					'center' => array( 'title' => esc_html__( 'Center', 'storzen' ), 'icon' => 'eicon-text-align-center' ),
					'right'  => array( 'title' => esc_html__( 'Right', 'storzen' ),  'icon' => 'eicon-text-align-right' ),
				),
				'default'   => 'left',
				'selectors' => array(
					'{{WRAPPER}} .sz-archive-title' => 'text-align: {{VALUE}};',
				),
			)
		);

		$this->end_controls_section();

		// ── Style tab ─────────────────────────────────────────────────────────

		$this->start_controls_section(
			'section_title_style',
			array(
				'label' => esc_html__( 'Title Style', 'storzen' ),
				'tab'   => Controls_Manager::TAB_STYLE,
			)
		);

		$this->add_control(
			'title_color',
			array(
				'label'     => esc_html__( 'Color', 'storzen' ),
				'type'      => Controls_Manager::COLOR,
				'default'   => '#111827',
				'selectors' => array(
					'{{WRAPPER}} .sz-archive-title' => 'color: {{VALUE}};',
				),
			)
		);

		$this->add_group_control(
			Group_Control_Typography::get_type(),
			array(
				'name'     => 'title_typography',
				'selector' => '{{WRAPPER}} .sz-archive-title',
			)
		);

		$this->add_group_control(
			Group_Control_Text_Shadow::get_type(),
			array(
				'name'     => 'title_shadow',
				'selector' => '{{WRAPPER}} .sz-archive-title',
			)
		);

		$this->add_responsive_control(
			'title_margin',
			array(
				'label'      => esc_html__( 'Margin', 'storzen' ),
				'type'       => Controls_Manager::DIMENSIONS,
				'size_units' => array( 'px', 'em', '%' ),
				'selectors'  => array(
					'{{WRAPPER}} .sz-archive-title' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
				),
			)
		);

		$this->add_responsive_control(
			'title_padding',
			array(
				'label'      => esc_html__( 'Padding', 'storzen' ),
				'type'       => Controls_Manager::DIMENSIONS,
				'size_units' => array( 'px', 'em' ),
				'selectors'  => array(
					'{{WRAPPER}} .sz-archive-title' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};',
				),
			)
		);

		$this->end_controls_section();
	}

	// ── Render ────────────────────────────────────────────────────────────────

	protected function render() {

		if ( ! $this->szp_wc_ready() ) {
			$this->szp_archive_placeholder( esc_html__( 'Archive Title — requires WooCommerce.', 'storzen' ) );
			return;
		}

		$s      = $this->get_settings_for_display();
		$source = $s['title_source'] ?? 'dynamic';

		// ── Resolve the title string ───────────────────────────────────────
		if ( 'static' === $source ) {
			$title = isset( $s['static_title'] ) ? trim( (string) $s['static_title'] ) : '';
		} else {
			$title = '';

			if ( function_exists( 'woocommerce_page_title' ) ) {
				/*
				 * woocommerce_page_title( $echo = false ) returns the title string.
				 * On a real archive page it resolves to:
				 *   - is_product_category() → single_cat_title( '', false )
				 *   - is_product_tag()      → single_tag_title( '', false )
				 *   - is_search()           → search term
				 *   - is_shop()             → WC shop page title
				 */
				$title = woocommerce_page_title( false );
			}

			// Fallback when on a non-archive or empty context.
			if ( '' === $title || false === $title ) {
				$title = isset( $s['fallback_title'] ) ? trim( (string) $s['fallback_title'] ) : '';
			}
		}

		// Silently render nothing on frontend when title resolves to empty.
		if ( '' === $title && ! $this->szp_is_archive_or_editor() ) {
			return;
		}

		// In editor show something useful when title is empty.
		if ( '' === $title ) {
			$title = esc_html__( 'Shop / Category Title', 'storzen' );
		}

		// Sanitise tag.
		$allowed_tags = array( 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'div', 'span', 'p' );
		$tag          = in_array( $s['tag'] ?? 'h1', $allowed_tags, true ) ? $s['tag'] : 'h1';

		printf(
			'<%1$s class="sz-archive-title">%2$s</%1$s>',
			esc_attr( $tag ),
			wp_kses_post( $title )
		);
	}
}
