<?php
/**
 * Cache module — Theme Compat: Elementor (and Elementor Pro)
 *
 * Elementor stores per-page rendered CSS at /wp-content/uploads/elementor/css/post-{ID}.css.
 * When the user edits a page, Elementor regenerates that file but the HTML
 * cache still references the old timestamp. We therefore listen to Elementor's
 * cache-clear hooks and purge our cache in lockstep.
 *
 * @package BlaminhorEssentials
 */

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

class Blaminhor_Essentials_Cache_Theme_Compat_Elementor extends Blaminhor_Essentials_Cache_Theme_Compat_Base {

	public function id() {
		return 'elementor';
	}

	public function label() {
		return 'Elementor';
	}

	public function is_active() {
		return defined( 'ELEMENTOR_VERSION' );
	}

	public function register_hooks() {
		// Bidirectional purge sync.
		add_action( 'elementor/core/files/clear_cache', array( $this, 'purge_all' ) );
		add_action( 'elementor/maintenance_mode/mode_changed', array( $this, 'purge_all' ) );
		add_action( 'update_option__elementor_global_css', array( $this, 'purge_all' ) );
		// Editor save invalidates the per-post CSS file → purge.
		add_action( 'elementor/editor/after_save', array( $this, 'purge_all' ) );
	}

	public function purge_all() {
		if ( $this->parent->purge ) {
			$this->parent->purge->purge_all();
		}
	}

	public function delay_js_exclusions() {
		// Elementor's frontend animations + nav menus + carousels rely on
		// these being available synchronously; delaying them breaks scroll
		// animations, popups, AND dropdown menus (smartmenus is the cause of
		// the "submenu doesn't show on hover" report on Elementor Pro sites).
		// Each entry is matched against BOTH the WP handle AND the src URL,
		// so path-style entries hit even if Elementor uses unprefixed handles.
		return array(
			'elementor-frontend',
			'/elementor/assets/js/frontend',
			'/elementor/assets/js/preloaded',
			'/elementor-pro/assets/js/frontend',
			// Bundled libs Elementor ships in /elementor/assets/lib/* —
			// smartmenus (dropdowns), sticky, swiper (sliders), dialog
			// (popups), share-link, waypoints (scroll triggers).
			// Some are enqueued with handles like "smartmenus" or "swiper"
			// (no elementor- prefix), so the path is the only reliable match.
			'/elementor/assets/lib/',
			'/elementor-pro/assets/lib/',
		);
	}

	public function defer_js_exclusions() {
		return array(
			'#/jquery-?[0-9.]*(.min|.slim|.slim.min)?\.js#',
		);
	}

	public function rucss_safelist() {
		return array(
			'.elementor-',
			'.e-con-',
			'.e-loading',
			'.swiper-',
			// Elementor Pro popups and motion effects:
			'.elementor-popup-modal',
			'.elementor-motion-effects-',
		);
	}

	public function async_css_excluded_handles() {
		// Elementor's frontend stylesheet + per-post inline CSS ship in a fixed
		// order; flipping them to async preload swaps their application order
		// and breaks widget layouts (column gaps, container max-widths).
		return array(
			'elementor-frontend',
			'elementor-icons',
			'elementor-pro',
			'elementor-post-',
			'e-',
		);
	}
}
